asyncio.gather中需传入可await的协程,retry函数须为async def且内部用await asyncio.sleep实现指数退避,配合随机抖动与上下界;tenacity须用AsyncRetrying.aretry而非装饰器;重试应基于具体异常或响应状态精准判断。

asyncio.gather 里直接 await retry 函数会出错
很多人试图在 asyncio.gather 中直接传入带重试逻辑的协程,比如 await asyncio.gather(retry(fetch_url, url1), retry(fetch_url, url2)),结果报 TypeError: object async_generator can't be used in 'await' expression。这是因为没正确封装重试逻辑——retry 必须返回一个可 await 的协程对象,而不是生成器或装饰器返回的包装体。
实操建议:
立即学习“Python免费学习笔记(深入)”;
- 重试函数本身要定义为
async def,内部用while循环 +await asyncio.sleep控制退避 - 不要用装饰器(如
@retry)直接包裹协程后扔进gather,除非该装饰器明确返回协程对象(多数第三方库如tenacity默认不满足) - 若用
tenacity,必须配合AsyncRetrying并显式调用aretry方法,例如:await AsyncRetrying(...).aretry(fetch_url, url)
指数退避的 sleep 时间必须用 asyncio.sleep 而非 time.sleep
在异步上下文中混用 time.sleep 会阻塞整个事件循环,导致其他任务卡死。常见错误是写成 time.sleep(2 ** attempt),表面看退避生效了,但并发请求数实际降为 1。
实操建议:
立即学习“Python免费学习笔记(深入)”;
- 退避延迟必须用
await asyncio.sleep(delay),且delay建议加上随机抖动(jitter),避免大量任务在同一时刻重试:例如delay = min(60, (2 ** attempt) + random.uniform(0, 1)) - 最大退避时间要设上限(如 60 秒),否则第 10 次重试会等 1024 秒,远超合理范围
- 首次重试延迟建议从 0.1 或 0.5 秒开始,而非 1 秒——小延迟能更快恢复瞬时故障
retry 条件判断不能只靠 Exception 类型
仅捕获 Exception 或 ClientError 不够安全。比如 HTTP 503 响应应重试,但 404 或 400 就不该重试;又比如数据库唯一约束冲突(IntegrityError)是永久错误,而连接超时(OperationalError)才需要重试。
实操建议:
立即学习“Python免费学习笔记(深入)”;
- 在重试循环中,先
await目标协程,再用if判断返回值或异常细节:例如检查exc.status == 503或"timeout" in str(exc) - 避免在
except块里无差别重试——把except Exception:换成具体异常类列表,并对每类做不同处理 - 如果目标协程返回的是
Response对象,优先用状态码或字段判断,比依赖异常更稳定
使用 tenacity 库时要注意异步策略配置
tenacity 是最常用的重试库,但默认配置是同步的。直接写 @retry(wait=wait_exponential()) 会导致协程被当成普通函数调用,报 RuntimeWarning: coroutine 'fetch' was never awaited。
实操建议:
立即学习“Python免费学习笔记(深入)”;
- 必须用
AsyncRetrying类,且调用其aretry方法:async for attempt in AsyncRetrying(...): with attempt: -
wait_exponential的参数单位是秒,不是毫秒;multiplier控制增长斜率,min/max设上下界,例如wait_exponential(multiplier=0.1, min=0.1, max=60) - 搭配
stop_after_attempt(3)和retry_if_exception_type((aiohttp.ClientError, asyncio.TimeoutError))才算完整闭环
真正容易被忽略的是重试边界:网络抖动、服务限流、下游临时不可用——这些场景下重试才有意义;而参数错误、权限不足、数据不存在,重试只会放大问题。退避策略再漂亮,也得先分清“该不该重试”。


















