失败恢复与幂等
失败恢复先查清任务停在哪里、是否已经产生副作用,再决定重试、继续还是停下;幂等让同一操作的重复请求不重复生效。
理解与应用
失败恢复是让中断或出错的任务回到明确状态的方法。幂等则是一种重要保证:对同一个逻辑操作重复提交,效果应与执行一次一致。两者在智能体调用外部工具时经常相遇,因为模型、网络、服务端和结果保存都可能在不同时间失败。
假设助手把更正发票附到 R-204 后,没有等到服务器响应。现在至少有两种可能:请求没到达,或者附件已经保存、响应在路上丢了。把超时直接当成“没有提交”并再交一次,就可能产生重复附件。先读回提交状态,或用服务端支持的同一幂等键重试,才能区分并处理这两种情况。
幂等键代表的是同一个业务意图,不是每次 HTTP 尝试。重试应保持键和关键参数不变;拿着旧键改发另一张发票,服务端应拒绝。实际实现还需要原子地处理并发请求、持久保存操作结果,并约定记录保留期限。只在进程内用一个字典记“做过了”,服务一重启就失去保证。
不是所有失败都值得重试。短暂限流或网络故障可以采用有上限的退避,参数错误、权限拒绝和永久失败则需要修正或停止。无法核实副作用时,应保留“结果未知”,而不是随便标成失败后补做。多个系统只完成前半段时,撤销或补偿也可能产生新的费用和影响,需要按原任务授权判断是否能执行。
动手试一试:响应丢失后,重复请求不再新增附件
同一请求重复提交复用已有回执,改参数则被拒绝。这个单进程示例没有持久化、过期策略或并发控制,用来说明业务语义,不能直接充当生产幂等服务。
将代码保存为 example.py,使用 Python 3.10+ 运行 python3 example.py。仅使用标准库,无需密钥,不会调用外部模型。
Python 代码
receipts = {}
attachments = []
def submit(key, record, filename):
params = (record, filename)
if key in receipts:
old_params, receipt = receipts[key]
if old_params != params:
return "拒绝:同一操作标识的参数发生变化"
return receipt
attachments.append(params)
receipt = f"回执 {len(attachments)}"
receipts[key] = (params, receipt)
return receipt
print(submit("op-7", "R-204", "invoice-v2.pdf"))
print(submit("op-7", "R-204", "invoice-v2.pdf"))
print(submit("op-7", "R-204", "invoice-v3.pdf"))
print("实际新增附件数:", len(attachments))运行结果
回执 1 回执 1 拒绝:同一操作标识的参数发生变化 实际新增附件数: 1
常见误区
- 网络超时表示调用方没有拿到结果,不等于远端没有执行。
- 每次重试都换一个新幂等键,会把重复尝试变成多个独立操作。
- 自动撤销和补偿也可能有副作用,不能因为原步骤失败就默认获准执行。
前置与延伸
建议先读
相关概念
参考与版本
Apollo 原创讲解与教学示例。参考资料用于核对技术定义;核验日不代表资料的发布日期。
- AWS Builders’ Library:Making retries safe with idempotent APIs ↗
核对请求身份与幂等重试;超时并不能证明服务端没有完成操作。 · 核验:2026-10-10