ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

Agent 故障接管:检查点之外还缺一个 fencing token

Agent 故障接管:检查点之外还缺一个 fencing token

心跳超时后,把任务交给新 Worker,原 Worker 不一定真的停止了。它可能经历了一次长暂停,恢复以后继续把旧结果写进数据库。只记录“现在是谁持有租约”,还不够保护外部副作用。

LangGraph 的持久化说明把检查点与跨线程存储分开;它也明确指出内存检查点不会跨进程重启保留。官方文档 这给故障接管划了一条很实用的线:恢复上下文、分配所有权、阻止陈旧写入,需要分别设计。

接管后,存储端也必须认识新一任 Worker

fencing token 是单调递增的所有权代次。新 Worker 得到更大的代次,资源端拒绝旧代次的写入。它不是由旧 Worker 自觉检查的一面小旗,而是最终写入位置必须执行的约束。Kleppmann 在讨论分布式租约时,用这个机制解释暂停与延迟请求带来的风险。原文

即使代次检查正确,同一代次内的重试也可能重复提交,因此还需要操作幂等键。检查点中的“下一步”只是一条执行意图;如果外部系统已经产生副作用却没回 ACK,重新跑一遍仍可能重复扣款或重复创建资源。

让两个 Worker 在同一段程序里相遇

下面的资源端既记最高代次,也记已经提交的操作 ID。先让代次 8 写入,再提交代次 7 的迟到请求;陈旧请求必须失败,同一操作的重试则返回原结果。

图中的 7 与 8 是所有权代次,不是时间戳,也不是 Worker 的业务优先级。检查点回放把上下文送到新 Worker,资源端的 fencing 检查负责另一条防线。

class FencedResource: def __init__(self): self.highest_epoch = 0 self.values = {} self.operations = {} def write(self, epoch, operation_id, key, value): if epoch < self.highest_epoch: raise ValueError("stale owner") self.highest_epoch = epoch if operation_id in self.operations: previous = self.operations[operation_id] if previous != (key, value): raise ValueError("idempotency key reused with different input") return "already_committed" self.values[key] = value self.operations[operation_id] = (key, value) return "committed" resource = FencedResource() assert resource.write(8, "op-B", "answer", "new") == "committed" assert resource.write(8, "op-B", "answer", "new") == "already_committed" try: resource.write(7, "op-A", "answer", "late") except ValueError: pass else: raise AssertionError("stale worker overwrote new owner") assert resource.values == {"answer": "new"} print("epoch 7 rejected; epoch 8 retry committed only once")

例子跑通以后,还要验证什么

这段代码已在本地 macOS、CPython 3.9.6 下运行,实际输出为epoch 7 rejected; epoch 8 retry committed only once。它验证的是例子中的数据约束与分支,不包含线上服务的吞吐或延迟测量。

这个资源端是单进程教学对象,没有实现分布式一致性或崩溃持久化。真实数据库必须把代次比较、幂等检查和数据写入放在同一原子提交边界;不支持 fencing 的外部服务需要另外设计幂等或补偿。未运行 LangGraph、数据库接管或故障注入测试。

延伸阅读

  • LangGraph Persistence:检查点、持久化边界与内存存储的限制。
  • How to do distributed locking:2016 年对暂停、租约与 fencing 的原始工程论证。
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进