背景

依赖变慢时每层都重试三次,原本一次请求可能被放大成几十次。重试需要全链路预算,而不是固定循环次数。

核心判断

  1. 仅重试明确的暂时失败,并确认操作幂等。
  2. 退避加入随机抖动,同时受入口 deadline 限制。
  3. 只在一层负责重试,记录尝试次数与预算耗尽。

最小示例

下面保留核心逻辑;业务类型、调用入口和环境配置按项目补齐。

var lastErr error
for attempt := 0; attempt < 3; attempt++ {
    if err := ctx.Err(); err != nil {
        return err
    }
    lastErr = call(ctx)
    if lastErr == nil || !retryable(lastErr) {
        return lastErr
    }
    if attempt < 2 {
        if err := sleep(ctx, backoff(attempt)); err != nil {
            return err
        }
    }
}
return lastErr

边界与误区

示例中 call、retryable、sleep 和 backoff 是业务适配函数,sleep 必须响应取消。最后一次失败后不再等待,错误要保留最后一次调用结果。

验证方式

注入超时、永久拒绝和短暂故障,核对实际调用数;多实例同时失败时,检查抖动是否减少同步重试峰值。

小结

以请求 deadline 为总边界,对不可重试错误立即返回,并限制链路放大倍数。