Worker Service Architecture
定义
Worker Service Architecture 是 claude-mem 中用于承接 Hook 后台处理的一种解耦架构。它把“捕获事件”与“执行 AI 压缩和存储”拆成两段:前者由 Hook 快速完成,后者由独立 worker 异步完成。
核心目标:Hook 必须快速返回;慢操作不能阻塞 Hook。
在本文档中的语境
本文档讨论的是 Claude Code Hook 体系中的后台处理问题:Hook 触发频繁,而且对响应时间敏感,但 observation 的 AI compression 每条可能耗时 5–30 秒。如果在 Hook 内直接同步调用 AI 处理,会导致 Hook 阻塞,破坏整体交互体验。
因此该架构的基本策略是:Hook 只负责读取 stdin、写入队列、立即返回成功;worker 再轮询队列并调用 Claude SDK 做真正的慢处理。
为什么需要后台 Worker
性能矛盾
这个架构要解决的是一个明确的时间尺度冲突:
- Hook 侧目标是快速返回,整体应少于 1 秒。
- 实际上 AI compression 对每条 observation 可能耗时 5–30 秒。
结论:不能让 Hook 等待压缩完成,必须把处理异步化。
直接同步处理为什么不可取
如果 Hook 在收到输入后立刻执行完整处理链路,例如解析 observation、调用 Claude SDK、等待压缩结果、再写回数据库,那么单次 Hook 可能阻塞数秒到数十秒。这既违背了 Hook 的快速返回目标,也会让上层系统把记忆功能的延迟感知为主流程故障。
核心机制
1. Hook 侧:快速捕获并入队
Hook 的职责被压缩到最小:
- 从 stdin 读取输入。
- 解析出要保存的 observation。
- 将 observation 插入队列。
- 立即返回成功。
文档给出的目标时间分布非常明确:
- 读取 stdin:小于 1 ms
- 插入队列:小于 10 ms
- 总体返回:小于 20 ms
即使实现细节会有环境差异,设计目标仍然是让 Hook 明显快于 1 秒,并尽量接近“几毫秒到几十毫秒”的量级。
2. Worker 侧:慢速异步处理
worker 是独立于 Hook 的后台进程,负责消费队列中的 observation。其处理流程包括:
- 以固定频率轮询队列。
- 取出待处理 observation。
- 通过 Claude SDK 执行 AI 处理。
- 解析结果并存储。
- 在完成后将该 observation 标记为已处理。
文档中给出的轮询节奏与耗时特征是:
- Worker 每 1 秒轮询一次队列。
- 每条 observation 的 AI 处理大约需要 5–30 秒。
这意味着 worker 的职责不是“实时同步返回”,而是“尽快、稳定地完成后台任务”。
处理链路
端到端流程
整个架构可以概括为: Hook(捕获) → 队列(缓冲) → Worker(处理)
Hook 先读取 stdin、插入队列并立即返回成功。随后 worker 轮询队列、调用 Claude SDK 处理 observation,并在完成后标记已处理。
对 PostToolUse 的意义
在 PostToolUse 阶段,像 save-hook.js 这样的脚本并不负责完成整条 AI 压缩链路,而是把工具使用后产生的信息排队送入异步流程。这与 PostToolUse 页面中“排队进入 AI 压缩流程”的定义完全一致。
设计模式
Fire-and-Forget Hooks
该架构首先体现的是“发后即忘”模式:Hook 只发起任务,不等待任务完成。
原则:Hook 应立即返回,而不是等待处理结束。
这意味着正确的 Hook 设计不是直接 await processObservation(...),而是只执行快速的 enqueueObservation(...) 后返回成功。
Queue-Based Processing
第二个关键模式是基于队列的处理。队列把“事件捕获”和“实际处理”隔离开,成为二者之间的缓冲层。
原则:通过队列把 capture 与 processing 解耦。
这种设计带来的好处包括:
- 并行 Hook 执行更安全,不必互相等待。
- worker 失败不会直接影响 Hook 的返回。
- 重试逻辑可以集中在 worker 一侧。
- 更容易处理背压。
Graceful Degradation
第三个模式是优雅降级。记忆系统失败时,不应该拖垮 Claude Code 的主流程。
原则:memory 失败不应导致 Claude Code 失败。
具体表现是:当捕获 observation、写入队列或后续处理出错时,系统倾向于记录错误并继续,而不是把异常向上抛出阻塞主流程。
文档列出的失败模式包括:
- 数据库被锁定:跳过该 observation,并记录错误。
- worker 崩溃:由 Bun 自动重启。
- 网络问题:使用指数退避重试。
- 磁盘满:告警用户,并禁用 memory。
Progressive Enhancement
第四个模式是 Progressive Enhancement。其含义不是“memory 一定存在”,而是“核心功能在没有 memory 时也能正常工作,memory 只是增强层”。
没有 memory:Claude Code 正常工作。 "> 有 memory:Claude Code 在正常工作基础上获得跨会话上下文。 "> memory 出故障:退回到正常可用状态。
因此 Worker Service Architecture 的后台化、异步化和降级机制,本质上是在为 Progressive Enhancement 提供工程实现。
Worker 进程管理
技术选型:Bun
worker 使用 Bun 作为 JavaScript runtime 和进程管理器。文档给出的选择理由包括:
- 失败后可自动重启
- 启动快、内存占用低
- 内建 TypeScript 支持
- 跨平台,可在 macOS、Linux、Windows 上运行
- 不需要额外的独立进程管理器
生命周期管理
worker 可以由 Hook 自动启动:如果 worker 未运行,Hook 会触发启动流程。
文档中的说明是“Started by hooks automatically (if not running)”。
同时还提供了常见的运维命令:
npm run worker:start:启动 workernpm run worker:status:检查状态npm run worker:logs:查看日志npm run worker:restart:重启npm run worker:stop:停止
这里的重点不是命令本身,而是该架构假设 worker 是一个长期存在、可被自动拉起、可被独立观测和管理的后台进程。
Worker HTTP API
接口形态
worker 还暴露了一个基于 Express.js 的 REST API。它运行在每用户一个端口的模式上,默认端口公式为:
37700 + (uid % 100)
也可以通过
CLAUDE_MEM_WORKER_PORT覆盖默认端口。
主要端点
文档列出的端点包括:
GET /health:健康检查POST /sessions:创建 sessionGET /sessions/:id:获取 session 状态PATCH /sessions/:id:更新 sessionPOST /observations:将 observation 入队GET /observations/:id:获取 observation
为什么使用 HTTP API
采用 HTTP API 的原因有四点:
- 与语言无关,Hook 可以用任意语言实现
- 调试方便,可以直接用 curl
- 错误处理标准化
- 更适合表达异步交互
这说明 Worker Service Architecture 并不强依赖“Hook 和 worker 必须在同一语言、同一进程、同一调用栈内”,而是主动用 HTTP 作为解耦边界。
细节与边界
Hook 的成功不等于处理完成
在这种架构里,Hook 返回成功,只表示“输入已读取且已成功进入队列”或至少已完成快速捕获阶段;它不表示 observation 已被压缩、解析、存储。
这是理解异步架构最容易混淆的边界之一。
轮询不是实时完成
worker 每 1 秒轮询一次队列,因此即便 Hook 侧几乎瞬时返回,真正的处理也至少会受到轮询周期和队列长度影响。再叠加 5–30 秒的 AI compression 时间,最终完成时间通常显著晚于 Hook 返回时间。