Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Django and this thing called Channels

Django and this thing called Channels

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

Andrew Godwin

March 09, 2016
Tweet

More Decks by Andrew Godwin

Other Decks in Programming

Transcript

  1. 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. There are standard channel names: STANDARDS Clients have unique response

    channels: http.request websocket.connect websocket.receive !http.response.jaS4kSDj !websocket.send.Qwek120d
  3. 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. Channels are network-transparent, and protocol termination is separate from business

    logic process 1 process 2 protocol server worker server channels client socket
  5. 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. 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. 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. 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. EXAMPLE This notifies clients of new blog posts: def newpost(message):

    for client in client_list: Channel(client).send({ 'text': message.content['id'], })
  10. 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. 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. EXAMPLE You can offload processing from views: def upload_image(request): ...

    Channel('thumbnail').send({ 'id': str(image.id), }) return render(...)
  13. 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. EXAMPLE The HTTP channel just goes to the view system

    by default. routing = { # This is actually the default 'http.request': 'channels.asgi.ViewConsumer', }
  15. 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, } )