标准答案
- 每次等待时间可按 min(cap, base * 2^attempt) 加随机抖动计算。
- 按错误类型决定是否重试,并让所有尝试共享同一 deadline。
- 记录尝试次数和最终错误;不可幂等操作应使用幂等键或改为查询状态。
题目解析
指数退避让连续失败的请求逐渐拉开间隔,随机抖动避免多个客户端在同一时刻再次冲击下游。最大延迟和最大次数要与调用链 deadline 一起限制。
是否重试取决于错误是否暂时、操作是否幂等和剩余预算是否足够。网络超时不能证明写操作没有执行,支付、扣库存和发消息应先查询状态或使用幂等键。
执行器要记录每次尝试、退避时间和最终错误,并避免多层客户端同时重试。重试成功也不自动证明副作用只发生一次,业务记录仍要可验证。
代码示例
退避时间示意:
TypeScript
const exponential = Math.min(maxDelay, baseDelay * 2 ** attempt)
const delay = Math.random() * exponential
await sleepUntil(delay, deadline)常见误区
- 误区:每次固定延时重试。改正:使用有上限的指数退避和随机抖动,避免同步重试风暴。
- 误区:所有异常都重试。改正:只重试可恢复错误,并检查幂等、次数和下游容量。
- 误区:每次重试重置总超时。改正:所有尝试共享原始 deadline,剩余时间不足时快速失败或转异步。