An ordered, first-in-first-out, at-most
once queue with expiry and delivery to
only one listening consumer.
Identified by a unique unicode name.
WHAT IS A CHANNEL?
Slide 12
Slide 12 text
Producers
Consumers
Channel
Slide 13
Slide 13 text
There are standard channel names:
STANDARDS
Clients have unique response channels:
http.request
websocket.connect
websocket.receive
!http.response.jaS4kSDj
!websocket.send.Qwek120d
Slide 14
Slide 14 text
There are standard message formats:
STANDARDS
- HTTP request
- WebSocket close
- HTTP response chunk
But you can make your own
channel names and formats too.
Slide 15
Slide 15 text
But how do we do this without making
Django asynchronous?
Slide 16
Slide 16 text
Channels are network-transparent,
and protocol termination is separate
from business logic
process 1 process 2
protocol
server
worker
server
channels
client
socket
Slide 17
Slide 17 text
Async/cooperative
code, but none of
yours
process 1 process 2
protocol
server
worker
server
channels
client
socket
Your logic running
synchronously
worker
server
Slide 18
Slide 18 text
For runserver, we run them as threads
thread 1 thread 2
protocol
server
worker
server
channels
client
socket
worker
server
thread 3
process 1
Slide 19
Slide 19 text
A view receives a request and
sends a single response.
WHAT IS A CONSUMER?
A consumer receives a message and
sends zero or more messages.
Slide 20
Slide 20 text
EXAMPLE
This echoes messages back:
def ws_message(message):
text = message.content['text']
reply = "You said: %s" % text
message.reply_channel.send({
'text': reply,
})
Slide 21
Slide 21 text
EXAMPLE
This notifies clients of new blog posts:
def newpost(message):
for client in client_list:
Channel(client).send({
'text': message.content['id'],
})
Slide 22
Slide 22 text
EXAMPLE
But Channels has a better solution for that:
# Channel "websocket.connect"
def connect(message):
Group('liveblog').add(
message.reply_channel)
# Channel "new-liveblog"
def newpost(message):
Group('liveblog').send({
'text': message.content['id'],
})
Slide 23
Slide 23 text
EXAMPLE
And you can send to channels from anywhere:
class LiveblogPost(models.Model):
...
def save(self):
...
Channel('new-liveblog').send({
'id': str(self.id),
})
Slide 24
Slide 24 text
EXAMPLE
You can offload processing from views:
def upload_image(request):
...
Channel('thumbnail').send({
'id': str(image.id),
})
return render(...)
Slide 25
Slide 25 text
EXAMPLE
All the routing is set up like URLs:
from .consumers import ws_connect
routing = {
'websocket.connect': ws_connect,
'websocket.receive': 'a.b.receive',
'thumbnail': 'images.consumers.thumb',
}
Slide 26
Slide 26 text
EXAMPLE
The HTTP channel just goes to the view system
by default.
routing = {
# This is actually the default
'http.request':
'channels.asgi.ViewConsumer',
}