使用 asyncio.gather 时正确捕获 aiohttp TimeoutError

Correctly catch aiohttp TimeoutError when using asyncio.gather

这是我在 Stack Overflow 上的第一个问题,所以如果我做了一些愚蠢的事情或遗漏了什么,我深表歉意。

我正在尝试一次向多个 api 端点发出异步 aiohttp GET 请求以检查这些页面的状态:结果应该是以下形式的三元组 (url, True, "200") 如果 link 和 (url, False, response_status) 在"problematic link" 的情况。这是每次调用的原子函数:

async def ping_url(url, session, headers, endpoint):

    try:
        async with session.get((url + endpoint), timeout=5, headers=headers) as response:
            return url, (response.status == 200), str(response.status)
    except Exception as e:
        test_logger.info(url + ": " + e.__class__.__name__)
        return url, False, repr(e)

这些被包装到使用 asyncio.gather() 的函数中,该函数还创建了 aiohttp 会话:

async def ping_urls(urllist, endpoint):

   headers = ... # not relevant

   async with ClientSession() as session:
        try:
            results = await asyncio.gather(*[ping_url(url, session, headers, endpoint) \
                      for url in urllist],return_exceptions=True)
        except Exception as e:
            print(repr(e))
   return results

从 main 调用的整体如下所示:

    urls = ... # not relevant
    loop = asyncio.get_event_loop()
    try:
        loop.run_until_complete(ping_urls(urls, endpoint))

    except Exception as e:
        pass
    finally:
        loop.close()

这在大多数情况下都有效,但如果列表很长,我注意到一旦我得到一个

TimeoutError

执行循环停止,我在第一个超时后得到所有其他 urls 的 TimeoutError。如果我在最里面的函数中省略超时,我会得到更好的结果,但它不再那么快了。有没有办法控制单个 api 调用的超时,而不是控制整个 url 列表的大的一般超时?

非常感谢任何形式的帮助,因为这个问题我的学士论文陷入困境。

您可能想尝试为您的客户端会话设置会话超时。这可以像这样完成:

async def ping_urls(urllist, endpoint):
    headers = ... # not relevant

    timeout = ClientTimeout(total=TIMEOUT_SECONDS)
    async with ClientSession(timeout=timeout) as session:
        try:
            results = await asyncio.gather(
               *[
                    ping_url(url, session, headers, endpoint)
                    for url in urllist
                ],
                return_exceptions=True
            )
        except Exception as e:
            print(repr(e))

        return results

这应该将 ClientSession 实例设置为 TIMEOUT_SECONDS 作为超时。显然,您需要将该值设置为适当的值!