Production Deployment & the WebSocket/Blocking-Call Tradeoffs
Gunicorn + Uvicorn Workers
gunicorn -k uvicorn.workers.UvicornWorker -w 4 main:appA common production pattern: Gunicorn as the battle-tested process manager (spawning, monitoring, graceful restarts, timeouts), with each worker actually running the ASGI application via a Uvicorn-compatible worker class — combining Gunicorn's mature supervision with Uvicorn's ASGI request handling.
Nginx in Front
The same Nginx-in-front pattern used with WSGI/Gunicorn applies here: Nginx handles TLS termination and static assets, while Uvicorn (often behind Gunicorn) focuses on running the async application.
WebSockets & the Blocking-Call Trap
ASGI's protocol abstraction (not tied to one request/response cycle) is what lets Uvicorn support persistent, bidirectional WebSocket connections for real-time features — something WSGI's model doesn't fit. But since asyncio's event loop is single-threaded and cooperative, a blocking synchronous call inside an async handler stalls the entire loop, preventing any other concurrent request from being processed until it finishes — frameworks typically offer a way to run such blocking code in a separate thread pool to avoid this.
Lifespan Events & Alternatives
The lifespan protocol lets an application register startup/shutdown handlers (opening/closing a database pool) tied to the server process lifecycle. Hypercorn is a notable alternative ASGI server, sometimes chosen for HTTP/2 support Uvicorn historically handled differently.
Keep your own version of these notes — editable, searchable, and organised by your stack.
Start free