mirror of
https://github.com/django/daphne.git
synced 2025-04-21 17:22:03 +03:00
Start on some kind of general spec.
This commit is contained in:
parent
faa915cfc8
commit
3bcfea0421
194
docs/asgi.rst
Normal file
194
docs/asgi.rst
Normal file
|
@ -0,0 +1,194 @@
|
|||
PEP: XXX
|
||||
Title: ASGI (Asynchronous Server Gateway Interface)
|
||||
Version: $Revision$
|
||||
Last-Modified: $Date$
|
||||
Author: Andrew Godwin <andrew@aeracode.org>
|
||||
Status: Draft
|
||||
Type: Informational
|
||||
Content-Type: text/x-rst
|
||||
Created: ?
|
||||
Post-History: ?
|
||||
|
||||
|
||||
Abstract
|
||||
========
|
||||
|
||||
This document proposes a standard interface between network protocol
|
||||
servers and Python applications, intended to allow handling of multiple
|
||||
protocol styles (including HTTP, HTTP2, and WebSocket).
|
||||
|
||||
It is intended to replace and expand on WSGI, though the design
|
||||
deliberately includes provisions to allow WSGI-to-ASGI and ASGI-to-WGSI
|
||||
adapters to be easily written for the HTTP protocol.
|
||||
|
||||
|
||||
Rationale
|
||||
=========
|
||||
|
||||
The WSGI specification has worked well since it was introduced, and
|
||||
allowed for great flexibility in Python framework and webserver choice.
|
||||
However, its design is irrevocably tied to the HTTP-style
|
||||
request/response cycle, and more and more protocols are becoming a
|
||||
standard part of web programming that do not follow this pattern
|
||||
(most notably, WebSocket).
|
||||
|
||||
ASGI attempts to preserve a simple application interface, but provide
|
||||
an abstraction that allows for data to be sent and received at any time,
|
||||
and from different application threads or processes.
|
||||
|
||||
It also lays out new, serialisation-compatible formats for things like
|
||||
HTTP requests and responses, to allow these to be transported over a
|
||||
network or local socket, and thus allow separation of protocol handling
|
||||
and application logic.
|
||||
|
||||
Part of this design is ensuring there is an easy path to use both
|
||||
existing WSGI servers and applications, as a large majority of Python
|
||||
web usage relies on WSGI and providing an easy path forwards is critical
|
||||
to adoption.
|
||||
|
||||
|
||||
Overview
|
||||
========
|
||||
|
||||
ASGI consists of three different components - *protocol servers*,
|
||||
a *channel layer*, and *application code*. Channel layers are the core
|
||||
part of the implementation, and provide an interface to both protocol
|
||||
servers and applications.
|
||||
|
||||
A channel layer provides a protocol server or an application server
|
||||
with a ``send`` callable, which takes a channel name and message
|
||||
``dict``, and a ``receive_many`` callable, which takes a list of
|
||||
channel names and returns the next message available on any named channel.
|
||||
|
||||
Thus, rather than under WSGI, where you point the protocol server to the
|
||||
application, under ASGI you point both the protocol server and the application
|
||||
to a channel layer instance. It is intended that applications and protocol
|
||||
servers always run in separate processes or threads, and always communicate
|
||||
via the channel layer.
|
||||
|
||||
Despite the name of the proposal, ASGI does not specify or design to any
|
||||
specific in-process async solution, such as ``asyncio``, ``twisted``, or
|
||||
``gevent``. Instead, the ``receive_many`` function is nonblocking - it either
|
||||
returns ``None`` or a ``(channel, message)`` tuple immediately. Integrating
|
||||
this into both synchronous and asynchronous code should be easy, and it's
|
||||
still possible for channel layers to use an async solution (such as
|
||||
``asyncio``) if one is provided, and just provide the nonblocking call
|
||||
via an in-memory queue.
|
||||
|
||||
The distinction between protocol servers and applications in this document
|
||||
is mostly to distinguish their roles and to make illustrating concepts easier.
|
||||
There is no code-level distinction between the two, and it's entirely possible
|
||||
to have a process that does both, or middleware-like code that transforms
|
||||
messages between two different channel layers or channel names. It is
|
||||
expected, however, that most deployments will fall into this pattern.
|
||||
|
||||
|
||||
Channels and Messages
|
||||
---------------------
|
||||
|
||||
All communication in an ASGI stack is using messages sent over channels.
|
||||
All messages must be a ``dict`` at the top level of the object, and be
|
||||
serialisable by the built-in ``json`` serialiser module (though the
|
||||
actual serialisation a channel layer uses is up to the implementation;
|
||||
``json`` is just considered the lowest common denominator).
|
||||
|
||||
Channels are identified by a bytestring name consisting only of ASCII
|
||||
letters, numbers, numerical digits, periods (``.``), dashes (``-``)
|
||||
and underscores (``_``), plus an optional prefix character (see below).
|
||||
|
||||
Channels are a first-in, first out queue with at-most-once delivery
|
||||
semantics. They can have multiple writers and multiple readers; only a single
|
||||
reader should get each written message. Implementations should never
|
||||
deliver a message more than once or to more than one reader, and should
|
||||
drop messages if this is necessary to achieve this restriction.
|
||||
|
||||
In order to aid with scaling and network architecture, a distinction
|
||||
is made between channels that have multiple readers (such as the
|
||||
``http.request`` channel that web applications would listen on from every
|
||||
application worker process) and *single-reader channels*
|
||||
(such as a ``http.response.ABCDEF`` channel tied to a client socket).
|
||||
|
||||
*Single-reader channel* names are prefixed with an exclamation mark
|
||||
(``!``) character in order to indicate to the channel layer that it may
|
||||
have to route these channels' data differently to ensure it reaches the
|
||||
single process that needs it; these channels are nearly always tied to
|
||||
incoming connections from the outside world. Some channel layers may not
|
||||
need this, and can simply treat the prefix as part of the name.
|
||||
|
||||
Messages should expire after a set time sitting unread in a channel;
|
||||
the recommendation is one minute, though the best value depends on the
|
||||
channel layer and the way it is deployed.
|
||||
|
||||
|
||||
Handling Protocols
|
||||
------------------
|
||||
|
||||
ASGI messages represent two main things - internal application events
|
||||
(for example, a channel might be used to queue thumbnails of previously
|
||||
uploaded videos), and protocol events to/from connected clients.
|
||||
|
||||
As such, this specification outlines encodings to and from ASGI messages
|
||||
for three common protocols (HTTP, WebSocket and raw UDP); this allows any ASGI
|
||||
web server to talk to any ASGI web application, and the same for any other
|
||||
protocol with a common specification. It is recommended that if other
|
||||
protocols become commonplace they should gain standardised formats in a
|
||||
supplementary PEP of their own.
|
||||
|
||||
The message formats are a key part of the specification; without them,
|
||||
the protocol server and web application might be able to talk to each other,
|
||||
but may not understand some of what they're saying. It's equivalent to the
|
||||
standard keys in the ``environ`` dict for WSGI.
|
||||
|
||||
The key abstraction is that most protocols will share a few channels for
|
||||
incoming data (for example, ``http.request``, ``websocket.connect`` and
|
||||
``websocket.receive``), but will have individual channels for sending to
|
||||
each client (such as ``!http.response.kj2daj23``). This allows incoming
|
||||
data to be dispatched into a cluster of application servers that can all
|
||||
handle it, while responses are routed to the individual protocol server
|
||||
that has the other end of the client's socket.
|
||||
|
||||
Some protocols, however, do not have the concept of a unique socket
|
||||
connection; for example, an SMS gateway protocol server might just have
|
||||
``sms.receive`` and ``sms.send``, and the protocol server cluster would
|
||||
take messages from ``sms.send`` and route them into the normal phone
|
||||
network based on attributes in the message (in this case, a telephone
|
||||
number).
|
||||
|
||||
|
||||
Groups
|
||||
------
|
||||
|
||||
While the basic channel model is sufficient to handle basic application
|
||||
needs, many more advanced uses of asynchronous messaging require
|
||||
notifying many users at once when an event occurs - imagine a live blog,
|
||||
for example, where every viewer should get a long poll response or
|
||||
WebSocket packet when a new entry is posted.
|
||||
|
||||
While the concept of a *group* of channels could be
|
||||
|
||||
|
||||
Linearization
|
||||
-------------
|
||||
|
||||
The design of ASGI is meant to enable a shared-nothing architecture,
|
||||
where messages
|
||||
|
||||
|
||||
Specification Details
|
||||
=====================
|
||||
|
||||
A *channel layer* should provide an object with XXX attributes:
|
||||
|
||||
* ``send(channel, message)``, a callable that takes two positional
|
||||
arguments; the channel to send on, as a byte string, and the message
|
||||
to send, as a serialisable ``dict``.
|
||||
|
||||
* ``receive_many(channels)``, a callable that takes a list of channel
|
||||
names as byte strings, and returns immediately with either ``None``
|
||||
or ``(channel, message)`` if a message is available.
|
||||
|
||||
|
||||
Copyright
|
||||
=========
|
||||
|
||||
This document has been placed in the public domain.
|
Loading…
Reference in New Issue
Block a user