KEEL · 龙骨 · A CURRICULUM FOR THE AI ERA

11. 进程重启后,Run 如何接着走? — keel 龙骨

如果执行状态只保存在 Python 变量里,进程在“外部提交成功、保存本地回执之前”崩溃,重启后就无法判断下一步。持久化执行的目标不是让进程永不失败,而是让失败后仍能根据历史恢复。

如果执行状态只保存在 Python 变量里,进程在“外部提交成功、保存本地回执之前”崩溃,重启后就无法判断下一步。持久化执行的目标不是让进程永不失败,而是让失败后仍能根据历史恢复。

事件历史是恢复依据

1 run_started
2 proposal_received
3 command_created
4 preview_created
5 approval_granted
6 attempt_started
7 outcome_unknown
8 reconciliation_started
9 action_succeeded
10 run_completed

每个事件包含 run_id、command_id、序号、时间、类型、因果 ID、主体和脱敏 payload。序号与唯一约束防止重复追加。

Workflow 和 Activity 分开

持久化工作流系统通常要求流程决策可重放,而把网络、时间、随机数和外部副作用放入 Activity:

Workflow: 根据已有事件决定下一状态
Activity: 调用配置服务、发送通知、查询状态

重放 Workflow 不应再次发送通知。Activity 的结果先写入历史,随后流程从历史读取结果。这是 Temporal 等 durable execution 系统的重要边界。

恢复时先检查事实,不猜下一步

flowchart TD
    R[加载最后事件] --> S{最后稳定状态}
    S -->|ready| Q[检查幂等记录后调度]
    S -->|running 且 lease 有效| W[等待当前 worker]
    S -->|running 且 lease 过期| C[查询外部状态]
    S -->|unknown| C
    S -->|pending| O[轮询 operation ID]
    C --> N[对账后决定重试/完成/人工]

不能看到 attempt_started 没有 succeeded 就自动重试,因为崩溃点可能在外部提交之后。

Trace 要保留跨系统因果

至少关联:

trace_id -> run_id -> command_id -> attempt_id -> external_reference

关键指标包括成功率、unknown 比例、对账耗时、重复命中率、补偿率、人工接管率、P95/P99 延迟和每种 Adapter 的错误分布。

日志不能保存完整 prompt、凭据、cookie 或未脱敏的外部响应。可观测性本身也是数据泄露面。

生产映射

教学项目使用单进程事件列表和内存 Adapter 来展示状态语义。真实项目通常需要:

检查理解

下一章:完成一次可恢复的配置变更

进入 keel 阅读