asgiref Documentation

repository·main·Indexed 23 days ago

https://github.com/django/asgiref

Utility libraries for bridging synchronous and asynchronous Python code, specifically targeting the ASGI (Asynchronous Server Gateway Interface) standard. Includes tools for implementing stateless ASGI servers via StatelessServer, managing sync-to-async and async-to-sync wrappers, and supporting ASGI extensions such as zero-copy send, HTTP/2 server push, and HTTP early hints.

Tokens
8.4K
Snippets
9
Records
50
Agent score
79%

What's inside asgiref

  1. ASGI Application Frameworks

    main

    Various frameworks are built on top of ASGI for building web applications and APIs. Notable options include:

    • BlackSheep: Typed, fast, minimal framework with dependency injection and OpenAPI support.
    • Connexion: Spec-first/API-first framework using OpenAPI specifications. Can be used standalone or with other ASGI/WSGI frameworks.
    • Django/Channels: Adds asynchronous support to Django; the original driver for the ASGI project.
    • Esmerald: Modular and pluggable framework for scalable applications.
    • Falcon: Reliable, high-performance microservices framework. Supports both WSGI and ASGI.
    • FastAPI: Built on Starlette; uses Python type annotations for OpenAPI and JSON Schema.
    • Flama: Data-science oriented framework for deploying ML APIs.
    • Litestar: Opinionated framework with first-class typing and Pydantic integration.
    • Quart: A microframework intended to provide asyncio functionality similar to Flask.
    • Sanic: Unopinionated server and framework that can operate as an ASGI-compatible framework.
    • rpc.py: RPC framework supporting sync/async functions and generators.
    • Starlette: A minimalist ASGI library providing Request and Response classes.
    • MicroPie: Lightweight framework designed for high-concurrency and simplicity.
  2. ASGI Server Implementations

    main

    The following ASGI servers are available for running ASGI applications. Choose based on your protocol requirements (HTTP/1, HTTP/2, HTTP/3, WebSockets) and stability needs:

    • Daphne (Stable): The current ASGI reference server. Written in Twisted. Supports HTTP/1, HTTP/2, and WebSockets.
    • Granian (Beta): A Rust-based HTTP server. Supports ASGI/3, RSGI, and WSGI.
    • Gunicorn (Stable): A Python HTTP server for UNIX using a pre-fork worker model. Supports HTTP/1, HTTP/2, and WebSockets.
    • Hypercorn (Beta): Based on sans-io libraries. Supports HTTP/1, HTTP/2, HTTP/3, and WebSockets. Note: HTTP/3 requires the h3 extra.
    • Anycorn (Beta): A fork of Hypercorn using AnyIO for asyncio/Trio compatibility. Supports HTTP/1, HTTP/2, HTTP/3, WebSockets, and TLS. Note: HTTP/3 requires the h3 extra.
    • Uvicorn (Stable): A fast server based on uvloop and httptools. Supports HTTP/1 and WebSockets.
  3. What is ASGI and how does it relate to WSGI?

    main
    ASGI (Asynchronous Server Gateway Interface) is a standard interface designed to bridge async-capable Python web servers, frameworks, and applications. It serves as a spiritual successor to WSGI. While WSGI was designed for synchronous Python applications, ASGI supports both asynchronous and synchronous applications. It includes a WSGI backwards-compatibility implementation, allowing existing WSGI applications to run in an ASGI environment.
  4. What is the ASGI specification and how does it work?

    main

    ASGI (Asynchronous Server Gateway Interface) is a standard interface between network protocol servers (like web servers) and Python applications. It is designed to handle multiple protocol styles, including HTTP, HTTP/2, and WebSocket, by moving away from the synchronous request/response cycle of WSGI toward an asynchronous, message-based model.

    An ASGI implementation consists of two main components:

    1. Protocol Server: Terminates sockets and translates them into connections and per-connection event messages.
    2. Application: An asynchronous callable that lives inside the server. It is called once per connection and handles event messages as they occur.

    Unlike WSGI, ASGI applications must be async/await compatible coroutines (compatible with asyncio).

  5. Understand ASGI connection scope and events

    main

    ASGI operates on two main abstractions: Connection Scope and Events.

    Connection Scope

    The scope is a dictionary passed to the application at the start of a connection. It describes the connection's properties.

    • In HTTP, the scope lasts for a single request.
    • In WebSocket, the scope lasts for the entire duration of the socket connection.

    Events

    Protocols are decomposed into a series of events. The application reacts to events received via receive() and responds by sending events via send().

    • Receiving: Events are dict objects with a top-level type key (e.g., http.request, websocket.connect).
    • Sending: The application sends event dictionaries back to the client.

    Serializable Types

    Because events may be sent over a network, they must only contain these types:

    • Byte strings (bytes)
    • Unicode strings (str)
    • Integers (signed 64-bit range)
    • Floating point numbers (IEEE 754 double precision; no NaN or infinities)
    • Lists (tuples must be encoded as lists)
    • Dicts (keys must be Unicode strings)
    • Booleans
    • None
  6. Understand the ASGI connection model: Scope and Events

    main

    An ASGI connection is split into two distinct parts:

    • Connection Scope: A dictionary representing the protocol connection to a user. The scope survives for the entire duration of the connection (until it closes).
    • Events: Asynchronous messages sent between the server and the application.
      • The server sends events to the application as things happen on the connection.
      • The application sends events back to the server to transmit data to the client or signal state changes.

    An application is invoked by awaiting a callable with three arguments: the scope, a receive awaitable, and a send awaitable. The application is expected to run for the lifetime of the connection.

  7. How sync-to-async and async-to-sync wrappers work

    main

    The asgiref.sync module provides wrappers to bridge the gap between synchronous and asynchronous code styles:

    • AsyncToSync: Allows a synchronous subthread to wait while an asynchronous function is called on the main thread's event loop. Control returns to the thread once the async function finishes.
    • SyncToAsync: Allows asynchronous code to call a synchronous function. The synchronous function is executed in a threadpool, and control is returned to the async coroutine when the function completes.

    Thread Sensitivity and Performance

    By default, sync_to_async is designed for maximum compatibility with synchronous code by running all synchronous code in the same thread. This is controlled by the thread_sensitive parameter.

    • thread_sensitive=True (Default): Ensures code runs in a predictable thread (the main thread or a single shared subthread) to maintain compatibility with thread-bound resources like database connections.
    • thread_sensitive=False: Runs the code in a threadpool for better performance. Warning: Do not use this if your code relies on anything bound to specific threads (e.g., database connections).

    To disable thread sensitivity, use the decorator syntax:

    @sync_to_async(thread_sensitive=False)
    def my_function():
        pass
    @sync_to_async(thread_sensitive=False)
  8. Use ASGI extensions for custom functionality

    main

    Servers can provide optional, non-core functionality via extensions in the scope dictionary.

    An extension is a named entry in scope['extensions']. If a server supports an extension, it provides a dictionary under that extension's name. An application can check for the presence of an extension to know it can use custom event types.

    Example: A server providing a fullflush extension to allow flushing network buffers:

  9. Replace `threading.local` with `asgiref.local.Local`

    main

    The asgiref package provides a drop-in replacement for threading.local that is compatible with both threads and asyncio Tasks.

    Key features:

    • Context Proxying: It automatically proxies values from a task-local context to a thread-local context when using sync_to_async or async_to_sync, and vice-versa.
    • Thread/Task Safety: For strict thread- and task-safety, you can set thread_critical on the Local object.
  10. Understand HTTP & WebSocket ASGI Message Formats

    main

    The HTTP+WebSocket ASGI sub-specification defines how to transport HTTP/1.1, HTTP/2, and WebSocket connections within ASGI. It is designed as a superset of the WSGI format, allowing for translation between the two.

    Key concepts:

    • Spec Versions: Servers provide an asgi["spec_version"] in the scope. Use this to determine if specific features (like the reason key in WebSocket events or headers in WebSocket Accept responses) are supported. Spec versions are distinct from HTTP or ASGI versions.
    • HTTP Transport: Supports HTTP/1.0, HTTP/1.1, and HTTP/2. For HTTP/2, servers should provide different scopes for different requests on the same connection and handle multiplexing.
    • Header Handling: ASGI transports headers as lists of 2-element [name, value] lists. This preserves the exact order and duplicates as received. For HTTP/2, applications must handle Cookie headers carefully as they may appear repeatedly or be concatenated.
  11. Implement ASGI middleware

    main

    ASGI middleware acts as both a server and an application. It receives a scope, receive, and send, performs logic (potentially modifying them), and then calls the inner application.

    Important: When modifying the scope, you must make a copy of the scope dictionary before mutating it and passing it to the inner application. This prevents mutations from leaking upstream to other middleware or the server. You should only mutate the scope before handing control to the child application.

  12. How to detect TLS connections in ASGI

    main

    An ASGI application can determine if a connection is secured via TLS by checking for the presence of the "tls" key within the extensions dictionary of the connection scope object.

    If the "tls" key is present, the server supports this extension and the connection is over TLS. If the key is missing, the connection is either not over TLS or the server does not support this extension.