使用 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
作为超时。显然,您需要将该值设置为适当的值!
这是我在 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
作为超时。显然,您需要将该值设置为适当的值!