功能说明
Do 对可重试操作执行有限次尝试。每次失败后按 BaseDelay << shift 计算指数退避,用 MaxDelay 封顶,再按 Jitter 做上下浮动,减少多个客户端同时重试造成的惊群。每次等待都监听上下文取消;如果错误被标记为永久错误,立即停止并返回包装后的原因。
关键代码
shift := attempt - 1
if shift > 6 {
shift = 6
}
delay := cfg.BaseDelay * time.Duration(1<<shift)
if cfg.MaxDelay > 0 && delay > cfg.MaxDelay {
delay = cfg.MaxDelay
}
位移上限防止尝试次数很大时整数溢出,封顶则保证延迟不会无限增长。
使用注意
isRetryable通过errors.Is(err, errPermanent)判断,业务错误应使用%w包装哨兵错误。- 随机抖动使用全局
math/rand,并发安全,但结果不可复现;测试时可注入固定随机源。 - 只重试幂等操作,非幂等写入需要服务端幂等键。
- 上下文取消会中断等待并返回
ctx.Err(),不会继续下一次尝试。 - 最终错误用
%w包装最后一次失败,调用方仍可判断根因。
验证方式
示例中前两次返回临时错误,第三次成功,输出 transient attempts=3 err=<nil>;第二次运行返回永久错误,只尝试一次。把 Attempts 改为 1 或去掉 Jitter,可分别验证次数与固定延迟。