Django and this thing called Channels

Django and this thing called Channels

A talk I gave at Python SF Meetup, March 2016.

077e9a0cb34fa3eba2699240c9509717?s=128

Andrew Godwin

March 09, 2016
Tweet

Transcript

  1. 11.

    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?
  2. 13.

    There are standard channel names: STANDARDS Clients have unique response

    channels: http.request websocket.connect websocket.receive !http.response.jaS4kSDj !websocket.send.Qwek120d
  3. 14.

    There are standard message formats: STANDARDS - HTTP request -

    WebSocket close - HTTP response chunk But you can make your own channel names and formats too.
  4. 16.

    Channels are network-transparent, and protocol termination is separate from business

    logic process 1 process 2 protocol server worker server channels client socket
  5. 17.

    Async/cooperative code, but none of yours process 1 process 2

    protocol server worker server channels client socket Your logic running synchronously worker server
  6. 18.

    For runserver, we run them as threads thread 1 thread

    2 protocol server worker server channels client socket worker server thread 3 process 1
  7. 19.

    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.
  8. 20.

    EXAMPLE This echoes messages back: def ws_message(message): text = message.content['text']

    reply = "You said: %s" % text message.reply_channel.send({ 'text': reply, })
  9. 21.

    EXAMPLE This notifies clients of new blog posts: def newpost(message):

    for client in client_list: Channel(client).send({ 'text': message.content['id'], })
  10. 22.

    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'], })
  11. 23.

    EXAMPLE And you can send to channels from anywhere: class

    LiveblogPost(models.Model): ... def save(self): ... Channel('new-liveblog').send({ 'id': str(self.id), })
  12. 24.

    EXAMPLE You can offload processing from views: def upload_image(request): ...

    Channel('thumbnail').send({ 'id': str(image.id), }) return render(...)
  13. 25.

    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', }
  14. 26.

    EXAMPLE The HTTP channel just goes to the view system

    by default. routing = { # This is actually the default 'http.request': 'channels.asgi.ViewConsumer', }
  15. 28.
  16. 29.
  17. 33.

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