Skip to content
Advertisement

Asyncio combined with custom modules and aiohttp

I am trying to sleep a module for a couple seconds, while sleeping, the script should continue running.
When the sleep is over, the module should put data["found"] = True, but the code never reaches past asyncio.sleep()
The code should print:

  • “bulbasaur”
  • “do stuff” x 5
  • “bulbasaur”

But bulbasaur never comes back.

main.py:

# main.py
urls = {"pokemon": pokemon.data, "nba": nba.data}

async def get_data(session, url):
    async with session.get(url, headers=headers) as r:
        return await r.json()


async def execute_modules(data):
    if pokemon.data["found"]:
        asyncio.create_task(nba.find_name(data[0]))
    else:
        asyncio.create_task(pokemon.find_name(data[0]))
        asyncio.create_task(nba.find_name(data[1]))


async def main():
    async with aiohttp.ClientSession() as session:
        tasks = []
        for key, value in urls.items():
            if not value["found"]:
                tasks.append(asyncio.create_task(get_data(session, value["url"])))

        data = await asyncio.gather(*tasks)
        # print(data[1])
        await execute_modules(data)


if __name__ == "__main__":
    while True:
        asyncio.run(main())
        time.sleep(2)

pokemon.py:

import asyncio

data = {
    "url": "https://pokeapi.co/api/v2/pokemon/1",
    "found": False
}


async def find_name(pokemon):
    if pokemon["name"] == "bulbasaur":
        data["found"] = True
        print("bulbasaur found")
        await asyncio.sleep(10)
        data["found"] = False
    else:
        print("no bulbasaur")

nba.py

data = {
    "url": "https://www.balldontlie.io/api/v1/players/1",
    "found": False
}

async def find_name(nba):
    print("do stuff")

Advertisement

Answer

The issue lies in execute_models(). There you spawn 1-2 tasks but never wait for them to complete.

This means that the task is scheduled to run the next event loop iteration but there never comes another event loop iteration since you never await anything after spawning the task. So main() exits and asyncio.run() cancels all tasks left. What you need to do is use asyncio.gather() inside execute_models() or have execute_models() return the tasks it creates and put another asyncio.gather() inside main().

async def execute_modules(data):
    tasks = []
    if pokemon.data["found"]:
        tasks.append(asyncio.create_task(nba.find_name(data[0])))
    else:
        tasks.append(asyncio.create_task(pokemon.find_name(data[0])))
        tasks.append(asyncio.create_task(nba.find_name(data[1])))
    await asyncio.gather(*tasks)

Since it seems like you want the script to continue running and not wait for the sleep, you may want to put the while True loop inside main() and change time.sleep(2) to asyncio.sleep(2) instead of what I proposed above.

The important aspect here is that the event loop is kept alive so that the tasks aren’t cancelled and continue to run.

User contributions licensed under: CC BY-SA
6 People found this is helpful
Advertisement