mirror of
				https://github.com/django/daphne.git
				synced 2025-11-04 01:27:33 +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