主题
Service Worker 生命周期
本文引用的源码文件
本文引用的文件
目录
引言
本文聚焦 MV3 Service Worker 的生命周期管理,围绕启动、运行和终止三个阶段展开,重点说明以下能力:
- 保活机制:侧边栏长连接保活、任务级心跳、闹钟自动续跑。
- 状态持久化:内存状态与 IndexedDB、chrome.storage.local 的同步策略。
- 事件监听器注册与注销:页面事件、定时器事件、系统事件的处理流程。
- 调试技巧与常见问题:内存泄漏检测、性能优化建议、SW 重启恢复路径。
本仓库采用双进程架构:Chrome 扩展端(Manifest V3,Service Worker)与独立本地代理端 Agent(Node.js)。本文仅讨论扩展端 Service Worker 的生命周期;Agent 端运行时约束在仓库文档中另有说明。
项目结构与服务端进程定位
Service Worker 入口由 manifest 声明,实际逻辑集中在 src/background/index.js,并依赖多个 background 子模块与存储层。
graph TB Manifest["manifest.json<br/>声明 service_worker"] --> SW["src/background/index.js<br/>Service Worker 入口"] SW --> State["src/background/state.js<br/>会话状态/取消/keepalive 端口表"] SW --> AutoResume["src/background/auto-resume.js<br/>闹钟自动续跑"] SW --> DB["src/storage/db.js<br/>IndexedDB + chrome.storage.local 双写"] Panel["src/side_panel/chat-manager.js<br/>侧边栏"] --> |chrome.runtime.connect| SW
图表来源
- manifest.json#L47-L49
- src/background/index.js#L1-L20
- src/background/state.js#L227-L305
- src/background/auto-resume.js#L1-L24
- src/storage/db.js#L1-L30
- src/side_panel/chat-manager.js#L3236-L3260
章节来源
核心组件
- Service Worker 入口:负责初始化国际化、定时任务恢复、自动续跑接线、keepalive 端口处理、侧边栏路由、全局快捷键等。
- 会话状态与取消控制:维护 ReAct 循环取消标志、AbortController、工具级中止、keepalive 端口注册表与实例身份。
- 自动续跑闹钟:基于 chrome.alarms 的任务级保活与断点续跑决策。
- 存储层:IndexedDB 封装与 ReAct checkpoint 的双写策略(IndexedDB + chrome.storage.local)。
- 侧边栏:建立 keepalive 长连接,上报实例身份,驱动 API 调用。
章节来源
- src/background/index.js#L53-L95
- src/background/state.js#L1-L147
- src/background/auto-resume.js#L20-L55
- src/storage/db.js#L604-L799
- src/side_panel/chat-manager.js#L3236-L3260
架构总览
Service Worker 生命周期分为三个阶段:启动阶段完成初始化与数据自检;运行阶段通过 keepalive 端口、心跳与闹钟维持活跃;终止阶段由系统回收或显式卸载触发,但通过闹钟与 checkpoint 实现“可恢复”。
sequenceDiagram
participant Browser as "浏览器"
participant Manifest as "manifest.json"
participant SW as "Service Worker (index.js)"
participant Panel as "侧边栏 (chat-manager.js)"
participant Store as "存储层 (db.js)"
participant Alarm as "闹钟 (auto-resume.js)"
Browser->>Manifest : 加载扩展
Manifest-->>SW : 创建 Service Worker
SW->>SW : 初始化 i18n / 定时任务恢复 / 自动续跑接线
SW->>Store : 清理过期 checkpoint / DB 自检
Panel->>SW : chrome.runtime.connect("keepalive-<sessionId>")
SW->>Panel : 回传 HOST_TAB_RESOLVED
Panel->>SW : KEEPALIVE_IDENTITY(windowId)
Note over SW,Panel : 长连接保持 SW 存活
SW->>Alarm : startAutoResumeWatch()
Alarm->>Browser : 周期闹钟(30s)
Browser->>SW : onAlarm -> 扫描 checkpoint 并续跑
SW->>Store : saveReactCheckpoint/getReactCheckpoint
Note over SW,Browser : SW 被回收后由闹钟唤醒继续执行
图表来源
- manifest.json#L47-L49
- src/background/index.js#L53-L95
- src/background/index.js#L140-L218
- src/side_panel/chat-manager.js#L3236-L3260
- src/background/auto-resume.js#L61-L89
- src/storage/db.js#L633-L703
详细组件分析
Service Worker 启动流程
- 初始化国际化,读取语言偏好。
- 重建定时任务闹钟(从 DB 恢复)。
- 注册自动续跑闹钟处理器,扫描残留 checkpoint 并尝试续跑。
- 启动时清理过期 ReAct checkpoint,同时作为 DB 自检,验证 reactCheckpoints store 可访问。
- 恢复脱离窗口状态,避免 SW 终止竞态下 UI 异常。
flowchart TD Start(["SW 启动"]) --> InitI18n["初始化国际化"] InitI18n --> RestoreAlarms["恢复定时任务闹钟"] RestoreAlarms --> RegisterAutoResume["注册自动续跑处理器"] RegisterAutoResume --> CleanupExpired["清理过期 checkpoint / DB 自检"] CleanupExpired --> RestoreDetach["恢复脱离窗口状态"] RestoreDetach --> Ready(["就绪"])
图表来源
章节来源
保活机制与代码路径
保活由三层保障构成:
- 侧边栏长连接保活:侧边栏通过
chrome.runtime.connect('keepalive-<sessionId>')建立端口,SW 接收并记录端口,防止 Chrome 判定 SW 空闲而杀死。 - 任务级心跳:测试用例注释指出,任务执行期每 20s 主动调用轻量 API 重置闲置计时器(参考测试注释中的标准模式)。
- 闹钟自动续跑:主任务执行期间注册 30s 周期闹钟;SW 被杀后闹钟唤醒 SW,扫描残留 checkpoint 自动续跑。
sequenceDiagram
participant Panel as "侧边栏"
participant SW as "Service Worker"
participant State as "state.js"
participant Alarm as "auto-resume.js"
Panel->>SW : connect("keepalive-<sessionId>")
SW->>State : registerKeepalivePort(sessionId, port)
Panel->>SW : KEEPALIVE_IDENTITY(windowId)
SW->>State : setKeepaliveIdentity(sessionId, identity)
SW-->>Panel : HOST_TAB_RESOLVED(hostTabId)
Note over SW,Panel : 长连接存在 → SW 不被判定为空闲
SW->>Alarm : startAutoResumeWatch()
Alarm->>Alarm : create periodInMinutes=0.5
Alarm-->>SW : onAlarm -> handler()
SW->>SW : decideAutoResume() + resumeReactLoopFromCheckpoint()
图表来源
- src/side_panel/chat-manager.js#L3236-L3260
- src/background/index.js#L140-L218
- src/background/state.js#L236-L305
- src/background/auto-resume.js#L61-L89
章节来源
- src/side_panel/chat-manager.js#L3236-L3260
- src/background/index.js#L140-L218
- src/background/state.js#L236-L305
- src/background/auto-resume.js#L61-L89
状态持久化策略:内存状态与 IndexedDB 同步
- 内存状态:activeReactLoops、cancelledSessions、sessionAbortControllers、toolAbortControllers、keepalivePorts、keepaliveIdentities 等。
- IndexedDB:会话、归档会话、UI 原型、token 统计、ReAct checkpoint、书签、定时任务等。
- chrome.storage.local:配置、checkpoint 后备存储、跨重启消息恢复。
- 双写策略:saveReactCheckpoint 先写 chrome.storage.local(可靠),再尝试 IndexedDB(性能优化);getReactCheckpoint 优先 IndexedDB,失败降级到 chrome.storage.local。
flowchart TD
UpdateMem["更新内存状态"] --> DecidePersist{"是否需要持久化?"}
DecidePersist --> |是| WriteStorage["写入 chrome.storage.local"]
WriteStorage --> TryIDB["尝试写入 IndexedDB"]
TryIDB --> IDBOk{"IndexedDB 成功?"}
IDBOk --> |是| Done["持久化完成"]
IDBOk --> |否| Fallback["保留 chrome.storage.local 备份"]
DecidePersist --> |否| Done
图表来源
章节来源
事件监听器注册与注销流程
- 页面事件:sidePanel.onOpened/onClosed、tabs.onActivated/onRemoved、windows.onFocusChanged 等用于维护面板可见性与活动 tab 镜像。
- 定时器事件:chrome.alarms 周期闹钟用于自动续跑;clearInterval/clearTimeout 在工具级中止与任务结束时清理。
- 系统事件:chrome.runtime.onConnect(keepalive 端口)、onDisconnect(端口断开延迟复核通知)、onSuspend(活动存储刷新)。
flowchart TD RegisterEvents["注册事件监听器"] --> PageEvents["页面事件:sidePanel/tabs/windows"] RegisterEvents --> TimerEvents["定时器事件:alarms/setInterval"] RegisterEvents --> SystemEvents["系统事件:runtime.onConnect/onDisconnect/onSuspend"] PageEvents --> HandlePage["处理面板打开/关闭、tab 切换"] TimerEvents --> HandleTimer["处理闹钟/定时器清理"] SystemEvents --> HandleSystem["处理 keepalive 端口/挂起"] HandlePage --> Cleanup["必要时注销监听器"] HandleTimer --> Cleanup HandleSystem --> Cleanup
图表来源
- src/background/index.js#L260-L274
- src/background/index.js#L599-L618
- src/background/index.js#L140-L218
- src/background/activity-store.js#L120-L121
章节来源
- src/background/index.js#L260-L274
- src/background/index.js#L599-L618
- src/background/index.js#L140-L218
- src/background/activity-store.js#L120-L121
自动续跑与断点恢复
- 自动续跑决策:根据 checkpoint 的 interruptedReason、activeReactLoops、autoResumeAttempts 判断是否续跑。
- 闹钟周期:30s(最小周期),多任务并发共享一个闹钟,引用计数管理 start/stop。
- 恢复流程:SW 启动时扫描所有 checkpoint,对目标会话递增 autoResumeAttempts 并调用 resumeReactLoopFromCheckpoint。
flowchart TD
OnAlarm["闹钟触发"] --> GetAllCP["获取所有 checkpoint"]
GetAllCP --> Decide["decideAutoResume(checkpoints, activeReactLoops)"]
Decide --> Targets{"有目标会话?"}
Targets --> |是| SaveNext["保存 nextAttempts"]
SaveNext --> Resume["resumeReactLoopFromCheckpoint(sessionId)"]
Targets --> |否| End["结束"]
Resume --> End
图表来源
- src/background/auto-resume.js#L39-L55
- src/background/auto-resume.js#L61-L89
- src/background/index.js#L65-L81
章节来源
- src/background/auto-resume.js#L39-L55
- src/background/auto-resume.js#L61-L89
- src/background/index.js#L65-L81
依赖关系分析
Service Worker 入口依赖多个模块,形成清晰的层次结构:
- 入口层:index.js 协调各子系统。
- 状态层:state.js 提供会话状态、取消控制、keepalive 端口管理。
- 调度层:auto-resume.js 提供闹钟与续跑决策。
- 存储层:db.js 提供 IndexedDB 与 chrome.storage.local 操作。
- 界面层:chat-manager.js 建立 keepalive 连接并上报身份。
graph LR Index["index.js"] --> State["state.js"] Index --> AutoResume["auto-resume.js"] Index --> DB["db.js"] Panel["chat-manager.js"] --> Index State --> Logger["shared/logger.js"] AutoResume --> Logger DB --> Logger
图表来源
- src/background/index.js#L1-L20
- src/background/state.js#L1-L10
- src/background/auto-resume.js#L18-L19
- src/storage/db.js#L1-L3
- src/side_panel/chat-manager.js#L3236-L3260
章节来源
- src/background/index.js#L1-L20
- src/background/state.js#L1-L10
- src/background/auto-resume.js#L18-L19
- src/storage/db.js#L1-L3
- src/side_panel/chat-manager.js#L3236-L3260
性能与保活特性
- 长连接保活:通过 keepalive 端口减少 SW 被杀概率,适用于长时间 API 调用场景。
- 心跳机制:任务执行期定期调用轻量 API 重置闲置计时器,符合 Chrome 官方建议。
- 闹钟续跑:30s 周期闹钟确保 SW 被回收后仍能恢复任务,避免无限重试风暴。
- 存储优化:IndexedDB 提供高性能查询,chrome.storage.local 作为可靠后备。
[本节为通用指导,不直接分析具体文件]
调试与故障排查指南
- 内存泄漏检测:检查 keepalivePorts 是否正确注销,abortCurrentTool 是否清理工具级 AbortController。
- 性能优化:避免频繁 IndexedDB 写入,使用 withStore 的事务包装确保事务提交后再返回。
- SW 重启恢复:检查 checkpoint 是否成功双写,确认 getAllReactCheckpoints 合并逻辑正常。
- 常见问题:
- “No SW”错误:SW 终止竞态下 chrome API 可能为 undefined,需使用可选链保护。
- 面板无法关闭:检查 sidePanel.close 与 fallback 自关闭逻辑。
- 通知风暴:自动续跑耗尽次数后应静默,避免重复通知。
章节来源
- src/background/state.js#L307-L342
- src/storage/db.js#L154-L252
- src/background/index.js#L136-L140
- src/background/index.js#L682-L705
- src/background/auto-resume.js#L39-L55
结论
Service Worker 生命周期管理通过多层保活机制与状态持久化策略,确保了 MV3 扩展的稳定性和可靠性。侧边栏长连接、任务级心跳与闹钟自动续跑共同构成了保活体系;IndexedDB 与 chrome.storage.local 的双写策略保障了数据一致性。事件监听器的注册与注销流程清晰,便于调试与维护。通过合理的性能优化与故障排查方法,可有效提升用户体验与系统稳定性。
[本节为总结性内容,不直接分析具体文件]