tenacity中需显式配置wait_exponential实现指数退避,如wait_exponential(multiplier=1, min=0.1, max=60),并配合stop_after_attempt与stop_after_delay防止耗时失控。

tenacity 重试策略里怎么设置指数退避
tenacity 默认的 retry_if_exception_type 不带退避逻辑,必须显式指定等待策略。指数退避要用 wait_exponential,它基于失败次数按 2ⁿ × multiplier 计算等待时间(单位秒),默认 multiplier=1,min=0,max=10。
常见误用是只写 retry=retry_if_exception_type() 却漏掉 wait=...,结果变成“立即重试”,根本没退避效果。
-
wait_exponential(multiplier=1, min=0.1, max=60):推荐起手配置,避免首次等待为 0 秒,也防止单次等太久 - min 和 max 是硬限制,即使按公式算出来超出也会被截断
- multiplier 影响整体节奏,设为 0.5 可让第一次等待从 1s 缩到 0.5s,适合对延迟敏感的调用
捕获特定异常并触发指数退避重试
直接用 retry_if_exception_type 最稳妥,比如只对 requests.exceptions.Timeout 或自定义的 TransientError 重试,避免把 ValueError 这类编程错误也卷进去重试。
别用 retry_if_exception 配 lambda 判断异常信息——正则匹配容易漏或误判,且异常 message 可能随版本变。
立即学习“Python免费学习笔记(深入)”;
仅使用 Python 将 Claw Code 虚拟化框架与 OpenClaw 集成,提供 184 种工具和 200 多条命令,用于安全分析和代码质量...
- 多个异常类型传 tuple:
retry_if_exception_type((TimeoutError, ConnectionError)) - 若需更细粒度(如只重试 status=503 的 HTTP 错误),得配合
retry_if_result或自定义谓词函数 - 注意:自定义异常要确保能被 pickle(尤其在 multiprocessing 场景下)
重试次数太多导致总耗时失控怎么办
stop_after_attempt(3) 和 stop_after_delay(10) 必须组合使用。光设次数不设超时,遇到网络卡死可能等几十秒;光设超时不设次数,瞬时毛刺也可能触发大量重试。
例如 wait_exponential(multiplier=1, min=0.1, max=5) + stop_after_attempt(5),最坏情况总耗时 ≈ 0.1 + 0.2 + 0.4 + 0.8 + 1.6 = 3.1 秒;但如果 max 设成 60,第 5 次就可能单次等满 60 秒。
- 建议先用
stop_after_delay(5)卡死总时间底线 - 再配
stop_after_attempt(3)控制重试频次,二者取“先满足者” - 调试时加
before=before_log(logger, logging.DEBUG)看每次重试前的日志,确认退避是否生效
异步函数(async def)怎么用 tenacity 做指数退避
同步和异步不能混用:给 async 函数套 @retry 而不加 AsyncRetrying,会报 RuntimeWarning: coroutine 'xxx' was never awaited,甚至静默失败。
必须用 tenacity.AsyncRetrying 实例 + await retrying(...) 手动调用,不能直接装饰 async 函数(当前 tenacity 8.x 尚未支持 @retry 原生 async 装饰)。
- 正确写法:
retrying = AsyncRetrying( wait=wait_exponential(min=0.1, max=5), stop=stop_after_attempt(3), reraise=True ) await retrying.call(your_async_func, *args, **kwargs) - 不要用
async with AsyncRetrying(...) as retrying:—— 这个上下文管理器是为底层状态控制设计的,普通场景 call 更直白 - 若用
aiostream或httpx.AsyncClient,确保被重试的函数本身是协程对象(即返回Coroutine)
stop_after_delay 和 wait_exponential 的 max 参数协同关系——前者管总账,后者管单次,两个值没对齐就会出现“以为最多等 5 秒,结果第 3 次重试卡了 60 秒”的情况。

















