You need to enable JavaScript to run this app. asyncio搭配backoff仅重试失败API而非整批请求的方案问询
优惠活动
大模型
产品
解决方案
定价
更多

asyncio搭配backoff仅重试失败API而非整批请求的方案问询

问题根源

你当前的问题根源是把重试装饰器加在了整批请求的外层函数上,且单条请求触发429时直接抛出异常,导致外层函数触发重试逻辑,整批10个请求全部重新执行。调整逻辑的核心是把重试粒度从整批降到单个请求。

调整方案

1. 封装单个请求函数,将重试逻辑迁移到单请求层

把backoff装饰器从批量请求函数移除,转而装饰单个API请求的异步函数,让每个请求自己管理自己的重试逻辑,失败时不会影响其他已经成功的请求。
注意要把同步的time.sleep替换为异步的asyncio.sleep,避免阻塞整个事件循环。

# 单个请求的重试逻辑,装饰器加在单请求函数上
@backoff.on_exception(backoff.expo, aiohttp.ClientError, max_tries=20, logger=my_logger)
async def fetch_single(session, url, params=None):
    async with session.get(url, params=params) as response:
        if response.status == 429:
            print("Code 429 received waiting for 2 minutes")
            # 必须用异步sleep,不能用同步time.sleep
            await asyncio.sleep(120)
            raise aiohttp.ClientError("Rate limit hit")
        return await response.read()

2. 修改批量请求逻辑

原来的批量请求函数不需要再加backoff装饰器,生成的任务列表直接对应每个带重试逻辑的单请求协程即可:

async def get_symbols(size, position):
    async with aiohttp.ClientSession() as session:
        # get_tasks内部调整为返回多个fetch_single(session, 接口地址, 请求参数)的协程对象
        queries = get_tasks(session, size, position)
        # 可选:加return_exceptions=True避免单请求重试彻底失败后中断整批任务
        responses = await asyncio.gather(*queries, return_exceptions=True)
        print("gathering responses")
        for result in responses:
            # 可以单独判断单个请求是否重试失败
            if isinstance(result, Exception):
                print(f"Single request failed after max retries: {str(result)}")
                continue
            # 正常处理返回的接口数据
            query_data = result
            # 后续业务逻辑
额外优化建议
  • 如果希望避免多个请求同时触发429导致多次重复等待2分钟,可以设置一个全局的限流等待标记,所有请求遇到429时先检查是否已经有其他请求在触发等待,避免重复等待浪费时间。
  • 可以根据API返回的429响应头里的Retry-After字段来动态调整等待时间,比固定等2分钟更合理。

内容的提问来源于stack exchange,提问作者Javip

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.11 09:33:03