先这样答
长任务中途崩溃(进程被杀、超时、报错退出)是常态而不是意外,恢复机制靠两个东西。第一是状态外置:每完成一步,把任务目标、计划、已完成步骤和关键产出写进进程外的持久化存储(数据库或文件),而不是只留在对话上下文里。重启后先加载状态、重建一个「压缩后的上下文」,从断点继续,而不是从零重跑。第二是幂等:写文件、执行命令、调外部接口这些有副作用的操作,都带唯一操作 ID,执行前先查这个 ID 做过没有,做过就跳过。读取类操作天然幂等不用管;创建类靠幂等键;删除、支付这类不可逆操作不能自动重试,必须人工确认或对账后处理。
最难的其实是「未知状态」:命令发出去了、结果还没回来进程就死了,这时既不能当没发生(可能已生效),也不能直接重试(可能重复执行)。正确动作是先对账——查文件是否存在、查远端资源实际状态——确认真实效果后再决定跳过还是重做。面试里主动把「未知状态对账」这一层讲出来,是区分「背过题」和「真踩过坑」的分水岭。
面试官会怎么追问
- 「上下文怎么恢复?把历史全部重放吗?」 不重放,又贵又可能超窗口。恢复的是状态摘要加最近几步:目标、计划、已完成步骤的压缩描述放回上下文,完整历史落库,需要细节时按需检索。
- 「怎么测试恢复逻辑是对的吗?」 主动注入故障:跑到第 N 步杀进程再重启,断言恢复后的最终结果和不崩溃的完整执行完全一致,包括没有重复的副作用。这个测试要进回归,不是测一次就完。
- 「断点粒度怎么定?」 粒度太细,持久化本身开销大;太粗,重做浪费。按「一个不可回退的外部动作」为边界切步:动作前存意图、动作后存结果,粒度跟着副作用走而不是跟着轮数走。
回答的坑
- 把恢复做成重跑:没有状态外置和幂等键,重跑就是重复副作用——重复发请求、重复写文件、重复扣减,用户看到的错误比崩溃更严重。
- 状态只存内存或只存对话历史:进程一挂全丢。持久化必须在进程外,且对话历史本身不能当唯一状态源,它只是日志。
同系列的题
—— 本题完 ——