retry装饰器默认只重试exception,需用exceptions参数显式指定如requests.exceptions.timeout等子类;重试关键在判断错误性质与响应码,而非仅设tries;异步中须用tenacity等支持await的库并替换为asyncio.sleep。

retry 库的 retry 装饰器为什么总不生效?
因为默认只重试 Exception,而很多网络或 IO 错误是更具体的子类(比如 requests.exceptions.Timeout),但装饰器没显式声明捕获范围,结果一报错就直接抛出去了。
- 必须用
exceptions参数明确指定要重试的异常类型,例如@retry(exceptions=(requests.exceptions.Timeout, requests.exceptions.ConnectionError)) - 别依赖
tries=3就以为能兜住所有失败——如果异常类型不匹配,一次都不会重试 -
delay和backoff控制间隔,但若底层请求本身带超时(如requests.get(..., timeout=0.5)),重试间隔再长也救不回瞬间失败
自己写 while 循环重试比用库更可控?
是的,尤其当你要区分临时性失败和永久性错误、或需要动态调整重试逻辑时。库封装太“厚”,反而容易掩盖判断逻辑。
- 典型场景:调用内部 API,返回
429 Too Many Requests要等几秒,但404或401再重试也没用 - 关键点不是“重试几次”,而是“什么响应该停,什么该等多久”——得解析响应体或状态码,而不是只看异常
- 示例节选:
for attempt in range(3):<br> try:<br> resp = requests.post(url, json=payload)<br> if resp.status_code == 429:<br> time.sleep(2 ** attempt)<br> continue<br> elif resp.status_code in (400, 401, 404):<br> raise RuntimeError(f"Non-retriable: {resp.status_code}")<br> return resp.json()<br> except requests.RequestException:<br> if attempt == 2:<br> raise<br> time.sleep(1)
异步任务(asyncio)里怎么安全重试?
不能直接套用同步的 retry 装饰器,它会阻塞事件循环;得用支持协程的方案,比如 tenacity 的 @retry 配合 await。
- 必须确认所用重试库真正支持
async def函数——retrying不行,tenacity可以 - 注意
sleep要换成await asyncio.sleep(),否则整个协程被锁死 - 如果重试逻辑里混用了同步 I/O(比如读文件、调用
subprocess.run),会拖慢整个 event loop,得用loop.run_in_executor包一层
重试不是加个装饰器就完事。最常漏掉的是:没区分错误性质、没控制好等待节奏、在异步上下文里用了同步等待。这些地方一错,重试反而放大问题。
立即学习“Python免费学习笔记(深入)”;










