Uvicorn: launch server as task?

Created on 9 Aug 2019  路  5Comments  路  Source: encode/uvicorn

Currently uvicorn.run() calls Server.run(...) which calls loop.run_until_complete(...). Additionally uvicorn insists on starting the loop itself too (in setup_loop)

As such, it is made very difficult to launch other tasks in the same process.

Is there a way to launch the server as just a task on the loop and have the ability to schedule additional tasks on the loop?

IIUC there were some related issues in the past but not clear to me what is going to happen with these.

Most helpful comment

Hi @toonknapen ,

This is a problem that I've had to solve, so I wrote a blog entry on it here. I think the bit right at the end might be what you're looking for.

All 5 comments

Hi @toonknapen ,

This is a problem that I've had to solve, so I wrote a blog entry on it here. I think the bit right at the end might be what you're looking for.

that article absolutely rocks @rob-blackbourn , thanks to you I got a nice and clean shutdown now, I struggled making it work properly before reading that beauty.

The starlette "translation" from your bareasgi example is rather simple now there is a app.state, just put the service you mention in your blog post in it, instead of in the info dictionnary and use the on_event methods of starlett in place of the startup_handlers

I feel like this could be added to the docs as it's a perfect example of using the uvicorn loop for doing something else in the same process !

@rob-blackbourn sorry to highjack the thread here, I think I found 2 issues with your setup, 1st is
pending, done = await asyncio.wait( [cancellation_task, asyncio.sleep(1)], return_when=asyncio.FIRST_COMPLETED )
I think it shoud be done, pending
the 2nd one is cancellation_task = self.cancellation_event.wait()
I think this should be cancellation_task = asyncio.create_task(self.cancellation_event.wait()), without it you never reach the task.cancel() part

@euri10 Spot on! I've fixed the blog :)

We've added a Config(loop="none") option now, if you really need it. Also see server.serve(...) if you want to run the uvicorn server from within an existing async context.

On the whole the ASGI lifespan messaging is the right way to include application startup or scheduled background tasks.

I'm wondering if we ought to include a startup=<some_func> and shutdown=<some_func> options, that hook in startup and shutdown tasks easily? That might be easier for folks in cases where they're not using an application framework that provides those hooks itself?

Was this page helpful?
0 / 5 - 0 ratings