Slide 1

Slide 1 text

Andrew Godwin @andrewgodwin DJANGO and this thing called CHANNELS

Slide 2

Slide 2 text

Andrew Godwin Hi, I'm Django core developer Senior Software Engineer at Likes complaining about networking

Slide 3

Slide 3 text

The Problem First: The Solution Then: The Future Finally:

Slide 4

Slide 4 text

The Problem WSGI ain't so bad

Slide 5

Slide 5 text

Browser HTTP Webserver Django WSGI View Handler

Slide 6

Slide 6 text

Browser WebSocket Webserver Django ???? ??? ????

Slide 7

Slide 7 text

Very hard to deadlock/cause errors Seems "Django-ish" DESIGN GOALS Scales decently All works inside runserver

Slide 8

Slide 8 text

Browser WebSocket Webserver Django Channels Consumers Routing

Slide 9

Slide 9 text

Browser HTTP Webserver Django Channels Consumer Ch. Routing View URL dispatch

Slide 10

Slide 10 text

The Solution A Series Of Channels

Slide 11

Slide 11 text

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', }

Slide 27

Slide 27 text

The Future What does it all mean?

Slide 28

Slide 28 text

WSGI

Slide 29

Slide 29 text

WSGI 2?

Slide 30

Slide 30 text

ASGI channels.readthedocs.org/en/latest/asgi.html

Slide 31

Slide 31 text

channel_layer.send(channel, message) channel_layer.receive_many(channels) + message standards + extensions (groups, stats)

Slide 32

Slide 32 text

Daphne HTTP/WebSocket ASGI server asgiref Memory layer, conformance suite, WSGI adapters asgi_redis Redis-based channel layer

Slide 33

Slide 33 text

Raw ASGI app example: while True: channel, message = layer.receive_many( ["http.request"], block = True, ) if channel is None: continue layer.send( message['reply_channel'], { 'content': 'Hello World!', 'status': 200, } )

Slide 34

Slide 34 text

Django 1.10

Slide 35

Slide 35 text

Django 1.10 And 1.8, 1.9 as a third-party app

Slide 36

Slide 36 text

It's all optional. No need to change anything if you don't want to use channels.

Slide 37

Slide 37 text

pip install channels channels.readthedocs.org

Slide 38

Slide 38 text

Thanks. Andrew Godwin @andrewgodwin