I am fairly new to asyncio
and I managed to do some requests with it. I made a function fetch_all()
that takes in a list of the queries (URLs) and the loop previously created with asyncio
as arguments, and calls the function fetch()
that gets the result of each query in JSON format:
import aiohttp
import asyncio
import ssl
import nest_asyncio
nest_asyncio.apply()
async def fetch(session, url):
async with session.get(url, ssl=ssl.SSLContext()) as response:
return await response.json()
async def fetch_all(urls, loop):
async with aiohttp.ClientSession(loop=loop) as session:
return await asyncio.gather(*[fetch(session, url) for url in urls], return_exceptions=True)
if __name__ == '__main__':
loop = asyncio.get_event_loop()
results = loop.run_until_complete(fetch_all(queries, loop))
This works properly, and I get the results of the queries in results
as a list of JSONs (dictionaries). But here goes my problem: sometimes, instead of the JSON, I get an error for some results (RuntimeError
, aiohttp.client_exceptions.ClientConnectorError
, etc.). I guess these are one-time errors, since if I redo the query individually I get the desired result. Hence, I came up with a while
loop to check which results are not dictionaries and redo their queries: I initialize repeat_queries
, error_index
and results
with the queries and their indices, and apply run_until_complete()
. Then I save each result that is a dictionary and update the list of the queries that are left and their indices:
repeat_queries = queries
error_index = list(range(len(repeat_queries)))
results = error_index
while error_index:
if __name__ == '__main__':
loop = asyncio.get_event_loop()
repeat_results = loop.run_until_complete(fetch_all(repeat_queries, loop))
for i, rr in zip(error_index, repeat_results):
results[i] = rr
error_index = [i for i in range(len(results)) if not isinstance(results[i], dict)]
repeat_queries = [repeat_queries[i] for i in error_index]
However, since the asyncio
loop is asynchronous, error_index
and repeat_queries
updates are executed before run_until_complete()
is done, and the loop is continuously running with queries that were already cast in the previous iterations, resulting in an (almost) infinite while
loop.
Therefore, my question is:
Is there any way to force some code to be executed after loop.run_until_complete()
has finished?
I have seen some similar questions in stackoverflow but I haven't been able to apply any of their answers.