Update deployment docs

This commit is contained in:
Andrew Godwin 2016-02-21 13:06:33 +00:00
parent 973b8b72ad
commit 3b8feb5b96
2 changed files with 46 additions and 39 deletions

View File

@ -34,19 +34,22 @@ serve as the communication layer - for example, the Redis backend connects
to a Redis server. All this goes into the ``CHANNEL_BACKENDS`` setting;
here's an example for a remote Redis server::
CHANNEL_BACKENDS = {
CHANNEL_LAYERS = {
"default": {
"BACKEND": "channels.backends.redis_py.RedisChannelBackend",
"HOSTS": [("redis-channel", 6379)],
"BACKEND": "asgi_redis.RedisChannelLayer",
"CONFIG": {
"hosts": [("redis-server-name", 6379)],
},
"ROUTING": "my_project.routing.channel_routing",
},
}
To use the Redis backend you have to install the redis package::
To use the Redis backend you have to install it::
pip install -U redis
pip install -U asgi_redis
Make sure the same setting file is used across all your workers, interfaces
Make sure the same settings file is used across all your workers, interfaces
and WSGI apps; without it, they won't be able to talk to each other and things
will just fail to work.
@ -88,44 +91,44 @@ do the work of taking incoming requests and loading them into the channels
system.
You can just keep running your Django code as a WSGI app if you like, behind
something like uwsgi or gunicorn, and just use the WSGI interface as the app
you load into the server - just set it to use
``channels.interfaces.wsgi:WSGIHandler``.
something like uwsgi or gunicorn; this won't let you support WebSockets, though.
Still, if you want to use a WSGI server and have it talk to a worker server
cluster on the backend, see :ref:`wsgi-to-asgi`.
If you want to support WebSockets, however, you'll need to run another
interface server, as the WSGI protocol has no support for WebSockets.
Channels ships with an Autobahn-based WebSocket interface server
that should suit your needs; however, you could also use a third-party
interface server or write one yourself, as long as it follows the
:doc:`message-standards`.
If you want to support WebSockets, long-poll HTTP requests and other Channels
features, you'll need to run a native ASGI interface server, as the WSGI
specification has no support for running these kinds of requests concurrenctly.
Channels ships with an interface server that we recommend you use called
*Daphne*; it supports WebSockets, long-poll HTTP requests, HTTP/2 *(soon)*
and performs quite well. Of course, any ASGI-compliant server will work!
Notably, it's possible to combine more than one protocol into the same
interface server, and the one Channels ships with does just this; it can
optionally serve HTTP requests as well as WebSockets, though by default
it will just serve WebSockets and assume you're routing requests to the right
kind of server using your load balancer or reverse proxy.
Notably, Daphne has a nice feature where it supports all of these protocols on
the same port and on all paths; it auto-negotiates between HTTP and WebSocket,
so there's no need to have your WebSockets on a separate port or path (and
they'll be able to share cookies with your normal view code).
To run a normal WebSocket server, just run::
To run Daphne, it just needs to be supplied with a channel backend;
first, make sure your project has an ``asgi.py`` file that looks like this
(it should live next to ``wsgi.py``)::
python manage.py runwsserver
import os
from channels.asgi import get_channel_layer
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "my_project.settings")
channel_layer = get_channel_layer()
Then, you can run Daphne and supply the channel layer as the argument:
daphne my_project.asgi:channel_layer
Like ``runworker``, you should place this inside an init system or something
like supervisord to ensure it is re-run if it exits unexpectedly.
If you want to enable serving of normal HTTP requests as well, just run::
python manage.py runwsserver --accept-all
This interface server is built on in-process asynchronous solutions
(Twisted for Python 2, and asyncio for Python 3) and so should be able to
handle a lot of simultaneous connections. That said, you should still plan to
run a cluster of them and load-balance between them; the per-connection memory
overhead is moderately high.
Finally, note that it's entirely possible for interface servers to be written
in a language other than Python, though this would mean they could not take
advantage of the channel backend abstraction code and so they'd likely be
custom-written for a single channel backend.
If you only run Daphne and no workers, all of your page requests will seem to
hang forever; that's because Daphne doesn't have any worker servers to handle
the request and it's waiting for one to appear (while ``runserver`` also uses
Daphne, it launches a worker thread along with it in the same process).
Deploying new versions of code
@ -145,3 +148,7 @@ There's no need to restart the WSGI or WebSocket interface servers unless
you've upgraded your version of Channels or changed any settings;
none of your code is used by them, and all middleware and code that can
customise requests is run on the consumers.
You can even use different Python versions for the interface servers and the
workers; the ASGI protocol that channel layers communicate over
is designed to be very portable and network-transparent.

View File

@ -332,7 +332,8 @@ store it in the session; thankfully, Channels ships with both a ``channel_sessio
decorator that works like the ``http_session_user`` decorator we mentioned above but
loads the user from the *channel* session rather than the *HTTP* session,
and a function called ``transfer_user`` which replicates a user from one session
to another.
to another. Even better, it combines all of these into a ``channel_session_user_from_http``
decorator.
Bringing that all together, let's make a chat server where users can only
chat to people with the same first letter of their username::
@ -343,8 +344,7 @@ chat to people with the same first letter of their username::
from channels.auth import http_session_user, channel_session_user, transfer_user
# Connected to websocket.connect
@channel_session
@http_session_user
@channel_session_user_from_http
def ws_add(message):
# Copy user from HTTP to channel session
transfer_user(message.http_session, message.channel_session)