python aiohttp into existing event loop
The problem is
run_app
is blocking. I want to add the http server into an existing event loop
run_app
is just a convenience API. To hook into an existing event loop, you can directly instantiate the AppRunner
:
loop = asyncio.get_event_loop()
# add stuff to the loop
...
# set up aiohttp - like run_app, but non-blocking
runner = aiohttp.web.AppRunner(app)
loop.run_until_complete(runner.setup())
site = aiohttp.web.TCPSite(runner)
loop.run_until_complete(site.start())
# add more stuff to the loop
...
loop.run_forever()
In asyncio 3.8 and later you can use asyncio.run()
:
async def main():
# add stuff to the loop, e.g. using asyncio.create_task()
...
runner = aiohttp.web.AppRunner(app)
await runner.setup()
site = aiohttp.web.TCPSite(runner)
await site.start()
# add more stuff to the loop, if needed
...
# wait forever
await asyncio.Event().wait()
asyncio.run(main())
For the future traveler from Google, here is a simpler way.
async def main():
await aio.gather(
web._run_app(app, port=args.port),
SomeotherTask(),
AndAnotherTask()
)
aio.run(main())
Explanation:
web.runapp
is a thin wrapper over internal function web._runapp
. The function uses the old style way of getting the eventloop and then calling loop.run_until_complete
.
We replace it with aio.gather
alongside other tasks that we want to run concurrently and use the aio.run
to schedule them
Source