功能说明
retry 是一个泛型异步重试函数,接受尝试次数、基础延迟和一个返回 future 的闭包。每次失败后按 base * 2^shift 计算等待时间,shift 最多 5,避免延迟无限增长,再加上按尝试次数计算的抖动毫秒数。次数耗尽后返回 RetryError,其中包含总尝试次数和最后一次错误文本。
关键代码
for attempt in 1..=attempts {
match operation(attempt).await {
Ok(value) => return Ok(value),
Err(error) => {
last = error.to_string();
if attempt < attempts {
let shift = (attempt - 1).min(5);
let delay = base * (1u32 << shift) + Duration::from_millis(jitter_ms);
sleep(delay).await;
}
}
}
}
闭包参数是当前尝试序号,便于调用方在日志或幂等键中使用。
使用注意
- 闭包类型是
FnMut,可以捕获并修改外部计数器,但同一个 future 不能并发复用。 - 抖动是确定性的,测试可复现;生产环境通常改用随机抖动打散重试。
- 只重试可恢复错误,参数校验失败等永久错误应在闭包内直接返回,避免浪费次数。
- 没有整体超时预算,长时间重试可能超过调用方容忍时间,外层应再包
timeout。 - 最后一次失败不再等待,直接构造错误返回。
验证方式
示例前两次返回错误,第三次成功,输出应为 Ok(3);把成功条件改为始终失败,可观察 RetryError { attempts: 4, last: ... }。调整 base 可测量总耗时变化。