Update backends docs, remove old message standards

This commit is contained in:
Andrew Godwin 2016-01-02 18:30:52 -08:00
parent d452486524
commit 3dec8e09b3
4 changed files with 39 additions and 213 deletions

View File

@ -6,18 +6,6 @@ Draft ASGI Spec
considered draft yet. Even the name might change; this is being written
as development progresses.**
::
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
========

View File

@ -1,28 +1,34 @@
Backends
========
Channel Layer Types
===================
Multiple choices of backend are available, to fill different tradeoffs of
complexity, throughput and scalability. You can also write your own backend if
you wish; the API is very simple and documented below.
you wish; the spec they confirm to is called :doc:`ASGI <asgi>`. Any
ASGI-compliant channel layer can be used.
Redis
-----
The Redis backend is the recommended backend to run Channels with, as it
The Redis layer is the recommended backend to run Channels with, as it
supports both high throughput on a single Redis server as well as the ability
to run against a set of Redis servers in a sharded mode.
To use the Redis backend you have to install the redis package::
To use the Redis layer, simply install it from PyPI (it lives in a separate
package, as we didn't want to force a dependency on the redis-py for the main
install):
pip install -U redis
pip install -U asgi_redis
By default, it will attempt to connect to a Redis server on ``localhost:6379``,
but you can override this with the ``HOSTS`` setting::
but you can override this with the ``hosts`` key in its config::
CHANNEL_BACKENDS = {
CHANNEL_LAYERS = {
"default": {
"BACKEND": "channels.backends.redis_py.RedisChannelBackend",
"HOSTS": [("redis-channel-1", 6379), ("redis-channel-2", 6379)],
"BACKEND": "asgi_redis.RedisChannelLayer",
"ROUTING": "???",
"CONFIG": {
"hosts": [("redis-channel-1", 6379), ("redis-channel-2", 6379)],
},
},
}
@ -49,72 +55,38 @@ settings. Any misconfigured interface server or worker will drop some or all
messages.
In-memory
---------
The in-memory backend is the simplest, and not really a backend as such;
it exists purely to enable Django to run in a "normal" mode where no Channels
functionality is available, just normal HTTP request processing. You should
never need to set it explicitly.
This backend provides no network transparency or non-blocking guarantees.
Database
--------
=======
Writing Custom Backends
-----------------------
The database layer is intended as a short-term solution for people who can't
use a more production-ready layer (for example, Redis), but still want something
that will work cross-process. It has poor performance, and is only
recommended for development or extremely small deployments.
Backend Requirements
^^^^^^^^^^^^^^^^^^^^
This layer is included with Channels; just set your ``BACKEND`` to
``channels.backends.database.DatabaseChannelLayer``, and it will use the
default Django database alias to store messages. You can change the alias
by setting ``CONFIG`` to ``{'alias': 'aliasname'}``.
While the channel backends are pluggable, there's a minimum standard they
must meet in terms of the way they perform.
In particular, a channel backend MUST:
In-memory
---------
* Provide a ``send()`` method which sends a message onto a named channel
The in-memory layer is purely an implementation detail used when running
the entire Django stack in a single process; the most common case of this
is ``runserver``, where a server thread, channel layer, and worker thread all
co-exist inside the same python process.
* Provide a ``receive_many()`` method which returns an available message on the
provided channels, or returns no message either instantly or after a short
delay (it must not block indefinitely)
You should not need to use this process manually, but if you want to,
it's available from ``asgiref.inmemory.ChannelLayer``.
* Provide a ``group_add()`` method which adds a channel to a named group
for at least the provided expiry period.
* Provide a ``group_discard()`` method with removes a channel from a named
group if it was added, and nothing otherwise.
Writing Custom Channel Layers
-----------------------------
* Provide a ``group_members()`` method which returns an iterable of all
channels currently in the group.
* Preserve the ordering of messages inside a channel
* Never deliver a message more than once (design for at-most-once delivery)
* Never block on sending of a message (dropping the message/erroring is preferable to blocking)
* Be able to store messages of at least 5MB in size
* Allow for channel and group names of up to 200 printable ASCII characters
* Expire messages only after the expiry period provided is up (a backend may
keep them longer if it wishes, but should expire them at some reasonable
point to ensure users do not come to rely on permanent messages)
In addition, it SHOULD:
* Provide a ``receive_many_blocking()`` method which is like ``receive_many()``
but blocks until a message is available.
* Provide a ``send_group()`` method which sends a message to every channel
in a group.
* Make ``send_group()`` perform better than ``O(n)``, where ``n`` is the
number of members in the group; preferably send the messages to all
members in a single call to your backing datastore or protocol.
* Try and preserve a rough global ordering, so that one busy channel does not
drown out an old message in another channel if a worker is listening on both.
The interface channel layers present to Django and other software that
communicates over them is codified in a specification called :doc:`ASGI <asgi>`.
Any channel layer that conforms to the :doc:`ASGI spec <asgi>` can be used
by Django; just set ``BACKEND`` to the class to instantiate and ``CONFIG`` to
a dict of keyword arguments to initialize the class with.

View File

@ -27,7 +27,6 @@ Contents:
getting-started
deploying
integration-changes
message-standards
scaling
backends
integration-plan

View File

@ -1,133 +0,0 @@
Message Standards
=================
Some standardised message formats are used for common message types - they
are detailed below. Message formats are meant to be generic and offload as
much protocol-specific processing to the interface server as is reasonable;
thus, they should generally represent things at as high a level as makes sense.
In addition to the standards outlined below, each message may contain a
``reply_channel``, which details where to send responses. Protocols with
separate connection and data receiving messages (like WebSockets) will only
contain the connection and detailed client information in the first message;
use the ``@channel_session`` decorator to persist this data to consumers of
the received data (or something else based on ``reply_channel``).
All messages must be able to be encoded as JSON; channel backends don't
necessarily have to use JSON, but we consider it the lowest common denominator
for serialisation format compatibility.
The size limit on messages is 1MB (while channel backends may support larger
sizes, all message formats should stay under this limit, which might include
multi-part messages where large content must be transferred).
The length limit on channel names is 200 printable ASCII characters.
HTTP Request
------------
Represents a full-fledged, single HTTP request coming in from a client.
Standard channel name is ``http.request``.
Contains the following keys:
* get: Dict of {key: [value, ...]} of GET variables (keys and values are strings)
* post: Dict of {key: [value, ...]} of POST variables (keys and values are strings)
* cookies: Dict of cookies as {cookie_name: cookie_value} (names and values are strings)
* headers: Dict of {header name: value}. Multiple headers of the same name are concatenated into one value separated by commas.
* meta: Dict of HTTP headers and info as defined in the Django Request docs (names and values are strings)
* path: String, full path to the requested page, without query string or domain
* root_path: Path designated as the "root" of the application (SCRIPT_NAME)
* method: String, upper-cased HTTP method
* server: [host, port] showing the address the client connected to
* client: [host, port] of the remote client
Should come with an associated ``reply_channel`` which accepts HTTP Responses.
HTTP Response
-------------
Sends either a part of a response or a whole response to a HTTP client - to do
streaming responses, several response messages are sent with ``more_content: True``
and the final one has the key omitted. Normal, single-shot responses do not
need the key at all.
Due to the 1MB size limit on messages, some larger responses will have to be
sent multi-part to stay within the limit.
Only sent on reply channels.
Keys that must only be in the first message of a set:
* content_type: String, mimetype of content
* status: Integer, numerical HTTP status code
* cookies: List of cookies to set (as encoded cookie strings suitable for headers)
* headers: Dictionary of headers (key is header name, value is value, both strings)
All messages in a set can the following keys:
* content: String of content to send
* more_content: Boolean, signals the interface server should wait for another response chunk to stream.
HTTP Disconnect
---------------
Send when a client disconnects early, before the response has been sent.
Only sent by long-polling-capable HTTP interface servers.
Standard channel name is ``http.disconnect``.
Contains no keys.
WebSocket Connection
--------------------
Sent when a new WebSocket is connected.
Standard channel name is ``websocket.connect``.
Contains the same keys as HTTP Request, without the ``POST`` or ``method`` keys.
WebSocket Receive
-----------------
Sent when a datagram is received on the WebSocket.
Standard channel name is ``websocket.receive``.
Contains the following keys:
* content: String content of the datagram.
* binary: Boolean, saying if the content is binary. If not present or false, content is a UTF8 string.
WebSocket Client Close
----------------------
Sent when the WebSocket is closed by either the client or the server.
Standard channel name is ``websocket.disconnect``.
Contains no keys.
WebSocket Send/Close
--------------------
Sent by a Django consumer to send a message back over the WebSocket to
the client or close the client connection. The content is optional if close
is set, and close will happen after any content is sent, if some is present.
Only sent on reply channels.
Contains the keys:
* content: String content of the datagram.
* binary: If the content is to be interpreted as text or binary.
* close: Boolean. If set to True, will close the client connection.