中断后怎样恢复而不重复写入
一句话收获:检查点、幂等、补偿和回滚解决不同问题。
这个场景在解决什么问题
这个场景讲的是:任务在写入前、写入中、写入后三个不同时机中断,分别该怎么恢复,才能不重复写入、不覆盖别人的修改。目标(goal)是演示检查点、幂等、版本冲突、补偿这四样机制的分工。观察点(observation)是:分别在"写入前、写入中、写入后"中断,看各自怎么处理。
为什么值得单独学?因为"中断恢复"最容易翻车的地方就是重复写入和覆盖冲突。这个场景告诉你:检查点、幂等、补偿、回滚这四样东西各管一摊,不能混用;恢复不是"从断点重跑一遍",而是根据"断在哪"选对机制。
先理清这条判断链(文字版)
这个场景的四步按"中断时机"分成三种情况,本质是"写入前 → 写入中(结果未知)→ 写入后(版本冲突/补偿回滚)":
- 写入前中断——还没产生副作用,可从已验证检查点继续,但恢复前要重读权限和外部状态。
- 写入结果未知(写入中)——超时后按幂等依据查询,发现对象其实已创建,防止重复副作用。
- 版本冲突(写入后)——中断期间外部对象被改了,旧计划不再合法,当前版本优先。
- 补偿或回滚——已发生业务副作用就补偿,软件版本故障才回滚,两者不能混。
这条链的核心逻辑是:断点位置不同,恢复机制不同;核心目标是"不重复写、不覆盖别人的改动、业务和技术影响分开处理"。
逐层详解
第 1 步:写入前中断
原文:尚未产生副作用,可从已验证检查点继续。
白话:如果中断发生在"写入之前"——也就是还没对外部世界产生任何副作用,那么可以从"已验证的检查点"继续。但注意:恢复前仍然要重读权限和外部状态,不能想当然。
类比:像你在付款前手机突然关机——钱还没扣,重新开机后(从检查点继续)当然可以,但你得再确认下账户还有效、订单还成立。
举例:Agent 已经准备好要调"创建订单",但还没发出去就中断了。恢复时从检查点继续,但先重读:账号权限是否仍有效、外部订单状态有没有变,然后才继续。
为什么重要:恢复前仍要重读权限与外部状态。也就是说,即使"看起来还没做",恢复时也依然要先重新验证权限和外部状态,因为中断期间世界可能变了。
怎么验证(证据点):
- 无外部回执:确实没有产生外部回执。
- 状态未变:外部状态没有变化。
- 检查点有效:检查点是有效的。
别踩的坑(边界):进程恢复不代表权限仍旧有效。意思是,进程重新跑起来了,不代表之前那个权限现在还有效——权限可能已被收回。
落地检查:先重新验证。也就是说,落地时恢复后第一步是重新验证权限和外部状态,而不是直接续跑。
第 2 步:写入结果未知
原文:超时后按幂等依据查询,发现对象已经创建。
白话:如果中断发生在"写入中"——写入发出去了但超时了、结果未知。这时候按幂等依据(幂等键)去查询,结果发现那个对象其实已经被创建了。于是确认"已经做过了",不再重复提交。
类比:像转账时网络卡住、你也不知道转没转出去——拿转账单号(幂等键)去查,发现钱已经转出去了,那当然不能再点一次转账。
举例:Agent 创建订单超时,拿幂等键查外部系统,发现订单 123 已经创建成功了。于是不再重新创建,而是把检查点更新为"已创建",继续后续流程。
为什么重要:幂等与状态查询防止重复副作用。也就是说,靠"幂等键 + 状态查询"这套组合,避免把已经做过的事再做一遍。
怎么验证(证据点):
- 对象已存在:查到对象已经存在。
- 提交次数唯一:提交次数是唯一的(没重复提交)。
- 状态可查:对象状态能查到。
别踩的坑(边界):再次提交相同写入请求并不等于任务已经恢复。意思是,即使你"再次提交了相同的写入请求"(幂等),也不代表整个任务就恢复了——那只是确认了这一步。
落地检查:将检查点更新到已创建。也就是说,落地时确认对象已创建后,要把检查点更新为"已创建"这个新状态。
第 3 步:版本冲突
原文:中断期间外部对象被修改,旧计划不再合法。
白话:如果中断期间,外部的那个对象被"别人"改过了(版本变了),那么你手里基于旧版本的计划就不再合法了。这时候要以"当前版本"为准,而不是硬拿旧计划去覆盖。
类比:像你和同事同时编辑同一份文档,你离线期间同事改了很多——你再上传旧版就会覆盖他的改动,正确做法是拿最新版重新合并。
举例:Agent 中断期间,订单状态被客服手动改成了"已取消",版本从 v3 变成 v4。Agent 手里基于 v3 的"继续退款"计划已不合法,必须按 v4 重新判断。
为什么重要:当前版本优先于旧检查点。也就是说,外部的最新版本优先于你存下来的旧检查点——旧计划要让位于现实。
怎么验证(证据点):
- 版本变化:外部对象版本确实变了。
- 旧候选冻结:基于旧版本的候选被冻结。
- 重新判断:触发重新判断。
别踩的坑(边界):强制覆盖会破坏外部变更。意思是,如果你无视版本变化、硬用旧计划覆盖,就会把别人已经做的改动破坏掉。
落地检查:进入重新规划或接管。也就是说,落地时遇到版本冲突,要进入"重新规划"或"交人接管",而不是强行覆盖。
第 4 步:补偿或回滚
原文:已发生业务副作用时执行补偿;软件版本故障时回滚。
白话:最后区分两种"补救":如果已经发生了业务副作用(比如钱已经扣了、货已经发了),要执行"补偿"(做反向操作或补救);如果只是软件版本坏了(部署出问题),才做"回滚"(回到上一个软件版本)。两者不能混用。
类比:像点外卖——餐已经送出去、你不想吃了,只能"补偿"(退款或退货);但如果只是 App 更新坏了,就"回滚"到旧版本。前者是业务补救,后者是技术回退。
举例:Agent 已经触发了"扣款"这个业务副作用,但后续中断,此时要"补偿"(发起退款);而如果只是代码部署了坏版本导致服务异常,才"回滚"到上一个稳定版本。
为什么重要:恢复、补偿和回滚不能混用。也就是说,"恢复任务""业务补偿""软件回滚"是三件不同的事,用错就会出大问题。
怎么验证(证据点):
- 副作用清单:已发生的业务副作用有清单。
- 补偿结果:补偿操作的结果被记录。
- 版本恢复:软件版本恢复到稳定状态。
别踩的坑(边界):回滚镜像不能抹去已发生的业务动作。意思是,把软件"回滚"到旧版本,并不能抹掉已经真实发生过的业务动作(比如已经扣的钱)。
落地检查:技术与业务影响分别处理。也就是说,落地时要把"技术层面的影响"和"业务层面的影响"分开处理,各用各的机制。
落地可行性小结
本场景涉及的技术栈和落地要点:检查点 Checkpoint、幂等(幂等键)、版本冲突(乐观锁/版本号)、补偿(compensation)、回滚(rollback)。
真实落地时要注意:写入操作要带幂等键,超时后才能查;外部对象要带版本号,才能检测到"中断期间被改了";补偿和回滚要严格区分——业务副作用用补偿,软件故障用回滚;恢复前必须先重读权限和外部状态。常见坑是:把"再次提交相同请求"当成"任务已恢复";以及遇到版本冲突时强行覆盖,破坏别人的修改。
回顾
- 断点位置不同(写入前/中/后),恢复机制不同。
- 写入前中断可从检查点继续,但要先重读权限和外部状态。
- 结果未知时靠幂等 + 查询防止重复副作用。
- 版本冲突时当前版本优先于旧检查点,不能强制覆盖。
- 业务副作用用补偿、软件故障用回滚,两者不能混用;回滚抹不掉已发生的业务动作。