20 · 可靠性、恢复与可观测性¶
一句话结论: Paperclip 把故障当作持久化状态机的一部分:run、lease、workspace operation、wakeup、watchdog 和 activity 都能被扫描、分类、重试或转成显式恢复路径,而不是依赖“进程应该还在”。
1. 可靠性目标¶
对多 Agent 控制面而言,可靠性不是“API 返回 200”,而是:
- 不重复执行同一任务;
- 不留下无 owner 的 in_progress;
- 不让终态被晚到事件覆盖;
- 不让成本/预算越过硬停后继续启动;
- 不让 workspace/lease/runtime service 永久泄漏;
- Server 重启后能解释每一条 active run;
- 人可以看到失败、证据和下一步。
2. Recovery Service 的视角¶
flowchart TB
T["periodic tick / startup / mutation"] --> SCAN["load durable facts"]
SCAN --> RUN{"run state coherent?"}
RUN -->|no| R1["terminalize / retry / mark lost"]
SCAN --> ISSUE{"issue has live path?"}
ISSUE -->|no| R2["release / wake / recovery issue"]
SCAN --> WS{"workspace/lease settled?"}
WS -->|no| R3["finalize / cleanup / expire"]
SCAN --> WATCH{"watchdog / monitor due?"}
WATCH -->|yes| R4["create idempotent review wake"]
R1 --> ACT["activity + notice + metrics"]
R2 --> ACT
R3 --> ACT
R4 --> ACT
Recovery 不是一个总开关,而是一组按问题分类的 reconcile service。
3. Startup Reconciliation¶
启动时至少需要检查:
- hot-restart intent/report;
- DB 中 running/queued/scheduled retry run;
- active process/provider metadata;
- Issue checkout/execution locks;
- environment leases;
- workspace operations;
- runtime services;
- plugin workers/jobs;
- stranded issues;
- task watchdog/issue graph liveness。
每项都应有分类结果,不能笼统改成 failed:adopted、finalized while down、lost、skipped、retryable、needs operator 等。
4. Hot Restart Hand-off¶
旧进程收到重启请求时写入 hot-restart-intent.json,包含:
- previous PID/identity/start time/version;
- requestedAt、reason、drainRequired;
- requestedByRun;
- preflight active run IDs;
- shutdown snapshot(run、adapter、process、issue、status)。
新进程启动后生成 report:
Intent/report 采用原子写入和 stale lock 处理,避免两个重启流程覆盖对方证据。
5. Orphan Run 处理¶
Run 有 process PID、group/provider reference 和 heartbeat timestamps。恢复时:
- 判断 process identity 是否仍属于本实例/run;
- 检查 provider 是否还能查询状态;
- 若已结束,读取结果并 finalization;
- 若仍活跃,adopt/继续监控;
- 若无法确认,标记 lost/failed 并创建 recovery path;
- 清理 Issue lock/lease 或保留明确等待状态。
不能简单以 PID 是否存在判断:PID 可能已被系统复用。
6. Stranded Issue Recovery¶
Issue liveness scanner 定期找:
- Agent-owned + nonterminal;
- 没有 queued/running/scheduled retry;
- 没有有效 wakeup/interaction wait;
- 没有合法 review/blocked path;
- 没有 active workspace finalization。
处理策略是保守的:
- 保留 owner 证据;
- retry 一次或 enqueue continuation;
- 留 recovery notice/action;
- 无法安全推进时 escalation/人工可见;
- 不因为“看起来卡住”就随意改 Agent/删除 workspace。
7. Task Watchdog¶
Task watchdog 关注配置 Issue 及其非 watchdog 子孙。当整棵子树停止且没有 live continuation 时:
- 计算 stop fingerprint(叶状态、blocker、interaction、配置);
- 与
lastReviewedFingerprint比较; - fingerprint 未变化则抑制重复;
- 创建/复用一个
originKind=task_watchdogreview Issue; - wake watchdog Agent;
- scope enforcement 限制它只能操作 monitored subtree。
它不是 silent-run monitor,也不是全局“看一切”。
8. Silent Active-Run Watchdog¶
另一个 scanner 关注仍为 running 的 process 是否长时间无输出。它使用:
- last event/log/progress;
- timeout threshold;
- provider/adapter classification;
- process health。
可能结果:发 ping、创建 stop decision、interrupt/retry、转 recovery。不要把它和 task watchdog 合并,否则 active silence 与 stopped subtree 会产生错误动作。
9. Task Watchdog 的 scope enforcement¶
Watchdog run context 携带 watchedIssueId/watchdogIssueId/companyId。路由层拒绝:
- 修改 watched subtree 外 Issue;
- 跨 Company mutation;
- 修改自身 watchdog 配置;
- 创建另一个 watchdog;
- 处理 Board-only approval/security-sensitive interaction;
- 绕过 typed reviewer/execution policy。
安全约束在 Server 执行,而不是写在 watchdog Prompt 里。
10. Recovery Action 与 Notice¶
恢复动作要成为可见资源:
- recovery action kind/status;
- source run/issue;
- recommended/allowed operation;
- actor/result/error;
- resolved time。
Notice/comment 应说明:
- 发现了什么证据;
- 系统采取了什么动作;
-
哪个 lock/lease/run 被影响;
-
还需要谁做什么。
这样 Board 不会看到任务“莫名其妙”回到 todo。
11. Provider Failure Classification¶
Adapter/provider 错误要分类:
| 类别 | 例子 | 恢复 |
|---|---|---|
| transient | 429、短暂网络、provider busy | scheduled retry |
| setup | binary/key/config 缺失 | fail fast + operator fix |
| auth | token 过期、grant revoked | reauth/approval,不盲重试 |
| workspace | provision/sync/finalize | operation retry/recovery |
| policy | budget/permission/approval | blocked/skip,等待治理 |
| logic | contract bug、invalid result | failed + visible escalation |
重试次数和 backoff 按类别,而非所有 Error 一样。
12. Scheduled Retry Promotion¶
Retry 记录 next attempt time、retry-of、reason、generation。Server tick 到期时:
- 检查 Company/Agent/budget/policy 是否仍可执行;
- 处理 Issue lock/workspace compatibility;
- 把 run/wakeup promotion 到 queued;
- 若条件仍不允许,重新 schedule 或 skipped with reason。
不要在 Worker 内 setTimeout 直到几小时后;进程重启会丢失。
13. Health 与 Runtime Service¶
Environment、connection、plugin worker、runtime service 都有 health read model。健康失败不一定等于直接删除:
- 记录 last check/message;
- 触发 degraded/error event;
- 阻断新 acquire 或 tool call;
- 保留外部 reference 以便修复;
- 背景 sweep 再检查。
14. Observability:结构化日志¶
Server middleware 对 request/run/plugin/tool 做结构化 logging 和 redaction:
- request ID/actor/company/run;
- route/action/status/latency;
- provider/adapter/error class;
- cleanup/recovery classification;
- secret/token/body redaction。
日志用于诊断,不替代 activity/cost/run event 的业务事实。
15. OpenTelemetry¶
当前 OTel 集成是 opt-in、traces only:
- 未设置
OTEL_EXPORTER_OTLP_ENDPOINT时不加载可选依赖; - 支持 grpc、http/protobuf、http/json exporter;
- HTTP、Express、PG 等 auto instrumentation;
- fs/dns/net 默认关闭以避免噪音;
- 不在此集成中导出 metrics/logs。
这表示结构化业务事件与 OTel trace 是互补的:trace 看请求/跨服务时间,DB event 看可审计业务事实。
16. 可靠性中的不可变证据¶
以下记录最好 append-only 或只允许受控状态推进:
- heartbeat run event/log;
- activity log;
- cost event;
- document revision;
- approval comment/resolution;
- tool invocation/audit;
- recovery action;
- plugin job run。
当前状态可以修正,历史证据不应被“恢复成功”覆盖。
17. 失败注入的关键问题¶
可靠性测试应问:
- 在 Issue checkout 后、Adapter 启动前崩溃会怎样?
- Adapter 已启动但 PID 尚未保存怎么办?
- Run terminal 写入后 lease release 失败如何恢复?
- cost 写入成功但 budget pause 失败会否继续启动?
- WebSocket 断线 30 秒,UI 是否能对账?
- plugin worker 在 action 中途退出,job 是否能重试?
- pipeline automation ledger 写入后进程崩溃,会不会重复创建 Issue?
这些问题比“HTTP 500 是否被捕获”更接近控制面可靠性。
18. 当前边界¶
- live event bus 进程内,无跨节点 replay;
- local process/runtime service 依赖持久主机;
- provider 状态可不可查询影响 adoption 质量;
- recovery scanner 复杂且可能产生保守的人工升级;
- OTel 不提供现成业务 metrics dashboard;
- plugin UI/Worker 的信任边界仍不同。
19. 可复用经验¶
- 把启动对账、运行扫描、lease sweep 和 watchdog 作为正式服务。
- 持久化 intent/report,让重启交接可解释。
- PID/Provider reference 要尽早记录,且按 identity 验证,不只看 PID。
- liveness scanner 按“没有下一跳”找问题,而不是按静态 status 猜。
- Retry 需要 failure classification、next time 和 generation。
- 恢复动作要变成可审查资源,不能只写 debug log。
- 业务 audit/event 与 trace/log 分层,分别服务事实与诊断。
源码入口¶
server/src/services/recovery/service.tsserver/src/services/recovery/issue-graph-liveness.tsserver/src/services/recovery/run-liveness-continuations.tsserver/src/services/issue-liveness.tsserver/src/services/task-watchdogs.tsserver/src/services/task-watchdog-scope.tsserver/src/services/hot-restart.tsserver/src/services/managed-resource-drift.tsdoc/TASK-WATCHDOG.mddoc/observability.md
可靠性必须被测试和发布流程持续验证:21 · 测试矩阵、CI 与发布。