Uvicorn Documentation

repository·main·Indexed 27 days ago

https://github.com/kludex/uvicorn

Uvicorn is a lightning-fast ASGI web server implementation for Python, supporting HTTP/1.1 and WebSockets. It provides options for minimal or standard installations, supports various event loop implementations including uvloop, winloop, and rloop, and implements the ASGI lifespan protocol for startup and shutdown events. The server includes built-in logging via uvicorn.error and uvicorn.access, with support for custom configuration via JSON, YAML, or INI files.

Tokens
13.7K
Snippets
29
Records
89
Agent score
94%

What's inside uvicorn

  1. Understand Uvicorn's built-in loggers

    main

    Uvicorn uses Python's built-in logging module and provides three specific loggers:

    • uvicorn: The parent logger (rarely used directly).
    • uvicorn.error: The general-purpose server logger for startup, shutdown, and errors. Note that despite its name, it is not limited to error messages.
    • uvicorn.access: Handles per-request access log lines.
  2. Quickstart: Create a basic ASGI application with uv and uvicorn

    main

    To set up a new project for running with Uvicorn, use uv to initialize the project, create an ASGI application in main.py, and add uvicorn as a dependency.

    1. Initialize the project:
      uv init app
    2. Create a simple ASGI application in app/main.py.
    3. Add uvicorn to your dependencies:
      uv add uvicorn
    4. Run the application locally:
      uv run uvicorn main:app
    uv init app
    uv add uvicorn
    uv run uvicorn main:app
  3. Configure Uvicorn using different methods

    main

    Uvicorn can be configured in three ways. Note that CLI options and programmatic arguments take precedence over environment variables.

    1. Command Line: Pass options directly to the uvicorn command.
    2. Programmatic: Pass keyword arguments to uvicorn.run().
      • Important: When using reload=True or workers=NUM, wrap the uvicorn.run call in an if __name__ == '__main__': block.
    3. Environment Variables: Use variables prefixed with UVICORN_ (e.g., UVICORN_HOST).

    Note: UVICORN_* environment variables cannot be used inside an environment configuration file passed via --env-file. The --env-file flag is intended for configuring your ASGI application, not Uvicorn itself.

  4. Read the request body in ASGI

    main

    To read the request body without blocking the asyncio task pool, you must fetch messages from the receive coroutine in a loop. Each message may contain a portion of the body and a more_body flag indicating if more data is coming.

    async def read_body(receive):
        """
        Read and return the entire body from an incoming ASGI message.
        """
        body = b''
        more_body = True
    
        while more_body:
            message = await receive()
            body += message.get('body', b'')
            more_body = message.get('more_body', False)
    
        return body
    
    
    async def app(scope, receive, send):
        """
        Echo the request body back in an HTTP response.
        """
        body = await read_body(receive)
        await send({
            'type': 'http.response.start',
            'status': 200,
            'headers': [
                (b'content-type', b'text/plain'),
                (b'content-length', str(len(body)).encode())
            ]
        })
        await send({
            'type': 'http.response.body',
            'body': body,
        })
  5. Deploy Uvicorn with Gunicorn

    main

    For production deployments, it is recommended to use Gunicorn as a process manager with the Uvicorn worker class.

    Note: The uvicorn.workers module is deprecated. You should install and use the uvicorn-worker package instead.

    python -m pip install uvicorn-worker
    gunicorn example:app -w 4 -k uvicorn.workers.UvicornWorker
  6. Understand the difference between --limit-concurrency and --backlog

    main

    It is important to distinguish between application-level and OS-level limits:

    1. --limit-concurrency (Application-level): Acts as a gate. Once the limit of open connections or in-flight tasks is reached, Uvicorn responds with a 503 Service Unavailable. Requests are not queued; they are rejected immediately.
    2. --backlog (OS-level): Bounds the kernel's accept queue for connections that have completed the TCP handshake but haven't been accept()ed by the worker. If this queue fills up, clients see connection failures or timeouts rather than a 503.

    To queue excess load instead of rejecting it, use a reverse proxy like Nginx in front of Uvicorn.

  7. Configure trusted proxies for forwarded headers

    main

    When running Uvicorn behind a proxy (like Nginx), request information such as the client IP and protocol can be lost. Uvicorn uses X-Forwarded-For and X-Forwarded-Proto headers to restore this information.

    To prevent IP spoofing, you must explicitly configure which clients are trusted to set these headers. You can trust:

    • IP Addresses: e.g., 127.0.0.1
    • IP Networks: e.g., 10.100.0.0/16
    • Literals: e.g., /path/to/socket.sock (for UNIX Domain Sockets)
    • All clients: Use the literal "*" (only use this if your proxy is guaranteed to strip existing headers before setting its own).

    Warning: Only trust clients you can actually control to avoid malicious actors spoofing their client address.

  8. Understand the ASGI WebSocket event lifecycle

    main

    Uvicorn translates WebSocket protocol messages into specific ASGI events that your application can handle.

    Events sent from Uvicorn to your ASGI app:

    • websocket.connect: Triggered when a client initiates a WebSocket upgrade request.
    • websocket.receive: Triggered when a message (text or bytes) is received from the client.
    • websocket.disconnect: Triggered when the connection is closed.

    Responses your ASGI app can send to Uvicorn:

    • websocket.accept: Accepts the connection upgrade. You can optionally specify a subprotocol.
    • websocket.send: Sends a message to the client.
    • websocket.close: Closes the connection. You can optionally specify a status code.