Skip to content
预计 1 分钟右侧目录可快速定位

重试怎样避免放大故障:Backoff、Retry Budget 与 Idempotency ​

前置:一次 Run 的时间预算怎么传下去:Timeout、Deadline 与 Retry 分类
核心问题:服务抖动时,为什么“多试几次”会放大故障,Backoff、Retry Budget 与 Idempotency 怎样共同限制重试?

100 个 worker 同时遇 429,如果都固定 1 秒后重试会再次同步冲击;随机抖动可分散请求。每个 Tool 最多 3 次不够;还应限制整 Run 总 retry 时间/次数,否则 20 个 Tool 各重试 3 次仍很危险。

Exponential Backoff / Jitter ​

Retry 解决一次暂时失败,但如果 100 个 Worker 都在同一秒失败,然后都“1 秒后重试”,恢复中的下游会再次被瞬间打满。

text
固定间隔:  100 clients → 1s → 同时 retry
Backoff:    1s → 2s → 4s → 8s
Jitter:     在每个等待区间随机打散

因此 exponential backoff 控制“越失败越少打扰”,Jitter 控制“不要所有实例同一时刻回来”。它只适用于可恢复且可安全重放的错误,并且仍要服从 Retry-After、deadline 和 retry budget。

Retry Budget ​

Retry Budget 给“失败后的额外尝试”设总上限,防止不同层各自 retry 后乘法放大。

例如 HTTP SDK 重试 3 次,ToolExecutor 再重试 3 次,Runtime 又重试 3 次,最坏可能产生 27 次底层请求。

因此一个 logical operation 应共享剩余 attempts / time / cost budget。每一层可以实现重试,但不能假设自己拥有无限的新预算。

Idempotency ​

Idempotency 解决的是:同一个 logical operation 被执行多次,业务效果仍然只发生一次。

例如支付请求第一次已经成功,但 response 丢失:

text
operation_id = pay-123
attempt 1 → remote success → response lost
attempt 2 → same operation_id
remote returns existing result

所以 idempotency key 必须跨 retry 保持稳定。它和 dedup 有关联,但更关注“重复执行的业务效果”,而不是只判断消息是不是见过。

🔍 源码对照:副作用 generation identity 是 Retry/Resume 的锚点之一 ​

完整源码与通用分析见 11-05 HITL / Approval / Resume。这里不重复代码;这里关注 idempotency:跨 retry / resume 保持稳定的 generation identity,是区分“同一副作用再次尝试”和“新的业务动作”的锚点。

源码说明

Auto-review gate 会在 side effect 启动时推进 approval identity;MCP tool metadata 又可以携带 idempotent hint。这两个机制放在同一案例里,能看出 Backoff 只是“何时重试”,Idempotency 才回答“重复执行是否安全”,ExecutionRecord 则回答“这一 attempt 到底已经走到哪一步”。

工程边界

Tool annotation 是提示,不是 exactly-once 保证。尤其远端写操作在 timeout 后可能处于 outcome unknown;单纯 exponential backoff 只会更礼貌地重复副作用。

Shadow Harness 对照

  • RetryBudget 属于 Run/operation,不允许嵌套库各自无限重试。
  • side-effect attempt 先生成 stable idempotency/execution key,再发生外部调用。

验证

设置三层 client/library/runtime 都想 retry 的场景,确保只有 Runtime 拥有总 retry budget,并验证最大外部调用次数。

Retry 的决定必须同时看错误和动作 ​

假设 create_ticket 返回网络超时。Runtime 不能只看到 TimeoutError 就立即重试,因为有两种完全不同的现实:

text
请求根本没到服务端          → retry 可能安全
服务端已创建 ticket,但响应丢失 → retry 可能创建第二张票

如果 API 支持 idempotency key,可以为同一次 logical operation 固定:

text
operation_id = run-42:create_ticket:node-7

所有 retry 使用相同 key;如果第三方不支持,就需要 query/reconciliation 决定第一次是否已经生效。

Retry Budget 则限制“整个 Run 最多为恢复错误付出多少代价”。例如单次 Tool 最多 3 次、整个 Run 最多 8 次 retry、剩余 deadline 少于 5 秒时停止重试。Exponential Backoff + jitter 只是控制什么时候再试,不能回答该不该再试。

Failure Modes ​

Idempotency Key 作用域设计错误 ​

症状: key 跨用户/资源复用,或每次 retry 都生成新 key。

为什么危险: 前者误去重不同操作,后者完全阻止不了重复副作用。

处理: key 绑定 logical operation + tenant/resource/arguments version,在 retry/resume window 保持稳定。

如何验证 ​

Case断言
Idempotency Key 作用域设计错误相同 logical operation 重放得到同一结果,不同 tenant/resource 不能命中同一记录。

关联源码 ​

自测 ​

  1. 下游大量 429 时所有 Worker 立即重试,为什么会形成 retry storm?Backoff、jitter、retry budget 各自抑制什么?
  2. 即使重试次数受限,有副作用操作没有 idempotency key 仍然危险。举一个重复提交的结果。

Sources ​

AI Engineering · Agent · Harness · Backend Systems