2

In an API developed using FastAPI framework, I am using asyncio to make calls to solr collections, but when I am calling asyncio.run(man(a,b)) from a python file query.py then I am getting asyncio.run() cannot be called from a running event loop.

in controller.py

@router.api_route()
async def api_call(a,b):
     #calling a function
     resp = query(a,b)
     return resp

in query.py

def query(a,b):
    result = asyncio.run(man(a,b))
    return result

in database_call.py

async def man(a,b)
      async with aiohttp.ClientSession() as session:

        url = ''
        async with session.get(pokemon_url) as resp:
            result = await resp.json()
            return result

when I am calling asyncio.run(man(a,b)) from query then I am getting asyncio.run() cannot be called from a running event loop. Kindly help me resolve the issue.

I tried: in query.py

def query(a,b):
    loop = asyncio.get_event_loop
    result = loop.create_task(man(a,b))
    return result

then I am getting <coroutine object main at 0x0394999ejt>

Chris
  • 18,724
  • 6
  • 46
  • 80
Amit
  • 171
  • 1
  • 6
  • In addition to the answer below, please have a look at [this answer](https://stackoverflow.com/a/71517830/17865804) as well. – Chris Feb 15 '23 at 10:15
  • You might also find Solution 2 of [this answer](https://stackoverflow.com/a/74071421/17865804) helpful. – Chris Feb 15 '23 at 10:20
  • I tried import nest_asyncio and then nest_asyncio.apply() in query.py and it is working but getting Runtimeerror : can not enter into task. – Amit Feb 15 '23 at 11:05

1 Answers1

2

The docs say that you should have only one call to asyncio.run in a program. "Should" doesn't mean the same thing as "must", so it's not a requirement. But it's a good guideline.

Solution 1: get rid of query entirely, and just await the coroutine man() directly.

@router.api_route()
async def api_call(a,b):
     return await man(a, b)

Solution 2: declare query to be an async def function, and await it:

@router.api_route()
async def api_call(a,b):
     #calling a function
     return await query(a,b)

async def query(a,b):
    return await man(a,b)

Solution 3: Do not declare query to be async def, but have it return an awaitable object. This is similar to what you tried in your last listing, but you need to await the result.

@router.api_route()
async def api_call(a,b):
     #calling a function
     return await query(a,b)

def query(a, b):
     return asyncio.create_task(man(a, b))

Solution 4: run query in another thread using the asyncio.to_thread function.

Solution 5: run query in a ThreadPool or ProcessPool.

The whole idea of asyncio (or any other form of parallel processing) is to allow the use of a task or a coroutine that does not finish immediately. It runs at a later time, and its result is not available until enough time has passed. Whether you use threading, multiprocessing or asyncio the situation is the same. If you need the answer from the coroutine/task/function in order for your program to continue, you need to wait for it somehow.

Paul Cornelius
  • 9,245
  • 1
  • 15
  • 24
  • My use case is such that I can not change in controller.py and query.py. I need to simply call main() using asyncio.run(main()) from query.py and store the result in a variable for further use. But I am getting asyncio.run() cannot be called from a running event loop. Is the any way I can get the desired result – Amit Feb 15 '23 at 10:13
  • 1
    And as the python interpreter is telling you, you can't run `asyncio.run` from a running event loop. What you can do is number 1 in this answer: just run `await main(a, b)`, which will run the `main` corutine in the already existing event loop. – M.O. Feb 15 '23 at 11:48