[英]Correctly catch aiohttp TimeoutError when using asyncio.gather
It is my first question here on Stack Overflow so I apologize if I did something stupid or missed something.这是我在 Stack Overflow 上的第一个问题,所以如果我做了一些愚蠢的事情或错过了什么,我深表歉意。
I am trying to make asynchronous aiohttp GET requests to many api endpoints at a time to check the status of these pages: the result should be a triple of the form ( url , True , "200" ) in case of a working link and ( url , False , response_status ) in case of a "problematic link".我正在尝试一次向许多 api 端点发出异步 aiohttp GET 请求以检查这些页面的状态:结果应该是形式的三元组( url , True , "200" )在工作链接的情况下和( url , False , response_status )在“有问题的链接”的情况下。 This is the atomic function for each call:这是每次调用的原子 function:
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)
These are wrapped into a function using asyncio.gather() which also creates the aiohttp Session:这些使用 asyncio.gather() 包装到 function 中,它还创建了 aiohttp Session:
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
The whole called from a main that looks like this:从一个看起来像这样的主调用的整体:
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()
This works most of the time, but if the list is pretty long, I noticed that as soon as I get one这在大多数情况下都有效,但如果列表很长,我一拿到就注意到了
TimeoutError
the execution loop stops and I get TimeoutError for all other urls after the first one that timed out.执行循环停止,在第一个超时之后我得到所有其他 url 的 TimeoutError。 If I omit the timeout in the innermost function I get somehow better results, but then it is not that fast anymore.如果我省略最里面的超时 function 我会得到更好的结果,但它不再那么快了。 Is there a way to control the Timeouts for the single api calls instead of a big general timeout for the whole list of urls?有没有办法控制单个 api 调用的超时,而不是控制整个 url 列表的一般超时?
Any kind of help would be extremely appreciated, I got stuck with my bachelor thesis because of this issue.任何形式的帮助都将不胜感激,由于这个问题,我的学士论文陷入困境。
You may want to try setting a session timeout for your client session.您可能想尝试为您的客户端会话设置会话超时。 This can be done like:这可以像这样完成:
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
This should set the ClientSession instance to have TIMEOUT_SECONDS
as the timeout.这应该将 ClientSession 实例设置为TIMEOUT_SECONDS
作为超时。 Obviously you will need to set that value to something appropriate!显然,您需要将该值设置为适当的值!
I struggled with the exceptions as well.我也为例外而苦苦挣扎。 I then found the hint, that I can also show the type of the Exception.然后我发现提示,我还可以显示异常的类型。 And with that create appropriate Exception handling.并以此创建适当的异常处理。
try: ...
except Exception as e:
print(f'Error: {e} of Type: {type(e)}')
So, with this you can find out, what kind of errors occur and you can catch and handle them individually.所以,有了这个,你可以找出发生了什么类型的错误,你可以单独捕获和处理它们。
eg例如
try: ...
except aiohttp.ClientConnectionError as e:
# deal with this type of exception
except aiohttp.ClientResponseError as e:
# handle individually
except asyncio.exceptions.TimeoutError as e:
# these kind of errors happened to me as well
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.