WebSockets: Intro to Messaging by Josue Balandrano Coronel

This video features Josue Balandrano Coronel at DjangoCon US 2016 in Philadelphia, Pennsylvania, USA.

WebSockets: Intro to Messaging by Josue Balandrano Coronel
0:44:33
Published August 10, 2016
2,025 views

DjangoCon US 2016 - WebSockets: Intro to Messaging by Josue Balandrano Coronel

Today’s web applications demand information to be delivered immediately after it is available. This is a huge step from where everything started, simple HTTP blocking requests. In order to solve this Server Side Events (SSE) and Websockets (WS) were created. SSE works from the server to the client only and it uses the HTTP protocol. WS is bidirectional and implements a layer on top of HTTP. WS started to get more momentum and now most of modern web browsers support it.

This talk was presented at: https://2016.djangocon.us/schedule/presentation/34/

LINKS:
Follow DjangCon US 👇
https://twitter.com/djangocon

Follow DEFNA 👇
https://twitter.com/defnado
https://www.defna.org/

Summary

WebSockets keep a TCP connection open after an HTTP upgrade, allowing the client and server to send messages in either direction with lower latency than repeated request-response cycles. Josue Balandrano Coronel explains why ordinary WSGI and thread-per-connection designs do not scale well for this model, then presents Django Channels as a Django-native architecture built around ASGI interface servers, channel backends, workers, consumers, groups, and per-client reply channels. He shows how Redis or IPC can connect workers and processes, how Daphne serves HTTP and WebSocket traffic, how consumers are routed, and how code outside Django can send messages through the channel layer. The examples include echoing messages, broadcasting to groups, retaining authentication and session context, and running a simple machine or service-monitoring workflow.

Key takeaways

  • WebSockets use an HTTP upgrade to establish a persistent TCP connection on which either side can send messages.
  • Keeping WebSockets inside a conventional WSGI request thread would consume threads indefinitely, so Channels offloads message handling to workers and asynchronous infrastructure.
  • Django Channels represents messages as FIFO channel queues with capacity, expiration, unique names, and at-most-once delivery semantics.
  • Consumers process channel messages, while groups make it possible to broadcast to multiple clients or servers and reply channels target one client.
  • ASGI interface servers such as Daphne create the channels used by WebSocket and HTTP connections, and routing maps those channels to consumers.
  • Memory, IPC, and Redis backends provide different levels of local or network-wide communication; Redis is the suggested production backend in the examples.

Summarised automatically from the transcript.

Chapters

  1. 0:00 WebSockets Fundamentals The talk introduces WebSockets, their persistent connections, and their advantages over traditional HTTP request-response communication.
  2. 2:33 WebSocket Servers and WSGI This chapter explains why regular WSGI workflows and thread-per-connection designs struggle to support WebSockets at scale.
  3. 6:30 Event-Driven Applications The speaker discusses asynchronous processing, worker limits, thread communication, and event-based server behavior.
  4. 7:17 Django Integration Approaches The talk compares Node.js, Python asynchronous frameworks, and WSGI offloading as ways to add WebSocket support to Django.
  5. 9:38 The Case for Django Channels Django Channels is introduced as a native, extensible abstraction for handling asynchronous work and WebSocket connections.
  6. 11:12 Channels Architecture The speaker outlines the interface server, channel backing, worker threads, and the flow of requests through Django Channels.
  7. 15:12 Messages, Consumers, and Groups This chapter covers message structure, consumer functions, reply channels, broadcasting, groups, routing, and the ASGI specification.
  8. 22:19 Channel Backends The talk compares memory, IPC, and Redis backends and explains how they enable communication between workers and processes.
  9. 24:35 Daphne and Interface Servers The speaker presents Daphne, ASGI deployment options, and configurations that combine Daphne with a conventional WSGI server.
  10. 27:00 External Channel Communication This chapter explains how applications and services outside Django can write to channels and communicate with connected clients.
  11. 29:18 WebSocket Demonstration A live example shows an echo server, external messages sent through a Django command, and channel identifiers in practice.
  12. 34:06 Authentication and Sessions The speaker explains how Django Channels preserves user and session information across the initial connection and later WebSocket messages.
  13. 36:07 Questions The presenter answers questions about deployment, backend persistence, Redis, reply channels, and possible future directions for Channels.

Transcript

7,651 words · auto-generated Show

Automatically transcribed, so expect mistakes in names and technical terms.

0:00

Speaker 1: Come on, no.

0:14

Speaker 2: Thank you. Uh good afternoon. So today is gonna be a day of firsts because this is my first DjangoCon. This is my first time I give a talk at a conference ever. This might be the first time that you guys hear about Django channels. The first time I wear this jacket too So let 's start. Why WebSockets? Why talk about WebSockets? Well the well the thing is that actually uh web applications have been growing more and more every year and now we have way more robust applications Not only on the on the back end but also on the front end. The front end interfaces are way more complex and they now need to talk to the to the server uh more regularly as well as the as the server, we're now processing more data on this on the server. So what this happens is that with our regular HTTP

1:02

Speaker 2: paradigm of request response, there's a lot of latency in this communication. And in order to solve this, some well, uh we created the the WebSockets specs And basically what WebSockets is, the idea behind WebSockets is to have a persistent connection between the client and the server. By having this persistent connection, we can just send information back and forth. and anybody can start sending the data, even the server or the client. With this we lower our latency and we have a better response and a real-time application We can see the difference on both protocols here, which is the HTTP, it just opens a connection, sends a request, then the server processes the request, sends the

1:47

Speaker 2: request back, I mean the response back, and it closes the connection while on WebSockets the channel is always open unless the client closes it or the server decides to close the the connection Uh so let's take a quick look at at the WebSockets spec, just some key points here. First of all, we need to realize that WebSockets still run on top of TCP/IP. It's just a percentage connection and also the way to start a WebSocket or to open a WebSocket is to give a uh to send an HTTP request, but it has an upgrade header on it And after this, the WebSocket is open and all the data that goes through it, it actually goes in frames that are called messages. We're gonna call these WebSocket messages just to avoid confusion So what about

2:33

Speaker 2: on the server side? What's happening? Because that's that's what we're here for. So let's take a look at at a WebSocket server under the hood. I'm not gonna go into much detail, but just the the overall overview So the first thing that we need to keep in mind is that WebSockets cannot be handled by regular WISGI workflow because if we take a look at the WISGI workflow, it is pretty much based on the regular HTTP request response paradigm. So whenever a client sends a request, the server processes it, and when the server is processing the request, we have this workflow right here, which is we uh the packet is probably gonna go through an HTTP server like Apache or Nginx And then it's gonna go to the WISGI server, which will then send all the information with header and a WISGI dictionary to Django. Django

3:18

Speaker 2: is going to process all that data and create the response, and then it will send it back to the to the client and the connection is gonna be closed. Now when this is happening here when when everything happens through the S thro through the WISGI server and then And then Django gets called and all that, that's happening on a thread. So if we would like to keep this same workflow and try to implement WebSockets, that will mean that whenever our response goes back This thread is not gonna finish. This thread is not gonna exit and we're gonna have to keep the thread running on an infinite loop just waiting for other messages either from the server to the client or from the client to the server Obviously this is not very scalable and we're gonna run out of threads very quickly. So one of the solutions

4:04

Speaker 2: actually is uh a concept that's called offloading And uploading is using one or more threads to handle slower learning running tasks, which can be managed in a non-blocking way. We can see that now our workflow changes a little bit. Usually in production what what we see with WebSockets is that a lot of people just runs two different WISG servers One of them is going to process all the HTTP requests the way that we all know. And the other one is going to process the WebSocket message. So now here's where things get interesting because when a WebSocket message comes in, what's happening is that the WISGI server actually fires up a worker thread, which will then process the request This is going to free the WISGI server to be able to handle any other concurrent requests that are gonna come into

4:54

Speaker 2: orb messages, WebSocket messages So this is an improvement on the whole on the whole workflow. But the thing here is that now we're starting to talk about threats, uh direct threats. We're talking about uh using threads to process the the request and how do we manage this? Well there's a lot of intricacies in the whole topic of this but the simple answer is just to use an async library something like gevn or or a sync IO uh there's a lot of different different uh libraries like this in in python Now the issue with this is that is that there's there's a lot of things that we need to keep in mind and there's a lot of caveats just when when we start diving into the whole asynchronous uh topic

5:40

Speaker 2: and and threat managing. So first of all, let's uh let's mention that offloading is not a new concept and other frameworks are using it like Node. js or maybe Go to We are diving into the async world and as I was mentioning. This has a lot of different different issues. One of them, well, there's a lot of different issues that can make us actually shoot ourselves on the foot very easily. And we need to to figure out also how to set how to make these threads to communicate with each other in order to uh to persist the data, let's say the session data or cookies data or things like that, because every thread that we fire up is gonna be working on a or is gonna be processing things on on a different context So there we we can't just put data on global variables and expect all the threads to know about

6:30

Speaker 2: those variables. Um The other but the cool thing is that by using this new workflow, now our application is event-based. Now Our our server is not going to send information only when the client clicks a button or refreshes a page or something like that, but we can also run long-running tasks on the server and whenever something happens on the server we can let the client know. One or many clients. There are still physical constraints, of course. This is another thing that we need to keep in mind, which is the amount of worker threads that we can actually use, the processing power, and the memory capacity Now, how to bring WebSockets into Django? Well there are different ways to do this.

7:17

Speaker 2: The the whole point of this talk is to talk about Jaguar channels, but I'm gonna talk about other projects that that try to actually do this just to see where those Django channels actually come from and what is Django Child's is it's actually trying to solve So the first solution that people came up with is to use just another entire complete different service to handle WebSockets like Node. js And this is going to change our workflow a little bit and it it will be something like this. So we can still use our HTTP server to to load balance different requests, the HTTP requests, they're gonna be handled by Django and the WebSockets can be handled by Node. js. Now the only thing is that we don't want to actually start developing things in two different languages on the server.

8:03

Speaker 2: So we might want to build a RESTful API so they both can talk and that way Node. js can get some information that it needs whenever a message comes in Uh this is this this is still is still putting a lot of different uh overhead on the whole communication of this Nevertheless, it is a solution that that people use out there. So the the other thing is that these are just two different uh technologies which can be hard to maintain sometimes. And it's really not Django native, it's more of a of a kind of hack. Although it works. The other thing is that we can just use another Python asynchronous event framework like a Twister or Tornado. So The idea is basically the same one a little bit, since we'll we'll be running Django in parallel with this other

8:53

Speaker 2: asynchronous event framework. And then we'll we we can we can make those two talk with each other. The other thing is to use Whiskey offloading uh and the uh and a way to actually make the threads to talk to themselves so that way we don't fall into into uh to the different issues that come with with different thread contexts is to use uh storage backing like Redis or something like that that every thread can actually read and write to So if we already have all these different solutions, they why talk about Django channels? Why is Django channels try to solve if we can already just use all of that? Well The thing is that, first of all, none of these solutions are actually Django native.

9:38

Speaker 2: I mean this these are just kind of things that you're running probably with Django and what we love and like and we want to to develop on its uh it's Django. The other thing is that all these solutions that I just mentioned they're really not malleable in the way that Django is malleable because Django lets us actually just replace or extend any piece of it the any way that that we want it maybe use a different library may maybe just a modify a library in some way or another uh or something like that. The other thing is that Django channels is trying to abstract the the uh the async handling of the entire offloading of the threads. That way we don't have to worry that much about it and and uh and we don't shoot ourselves on the foot that much.

10:27

Speaker 2: Uh the other thing is that also Django is always being very friendly with other technologies and and and and it's very easy to just um maybe run a script outside Django or something like that and make it talk to Django and and Django will will actually do a lot of pretty cool things with this So let's just overview again the the the the way that that we can actually implement offloading with WISGI because This is one of the things that that kind of kind of approaches more the model of Django channels. So as we remember we have two WISGI servers, which one of them is going to be handling the WebSocket uh connections and then fire all worker threads. So if we take a look at how Jago

11:12

Speaker 2: channels actually works We can see that this is a little bit like it, not necessarily the same, but the idea behind it is is the same one Whenever we have a packet come in, we're gonna have an interface server because the processing of the entire of all the requests or messages are going to happen on the worker threads then our our WISGI server or or our HTTP server actually becomes only an interface server which is a layer between our our Django projects and the wild out there Then after this we have a channel uh a channel backing which is the the the new thing that that we we're gonna talk about

11:58

Speaker 2: This is going to let us actually control the different information that all these worker threads are going to need in order to know when when they're gonna fire off and what do they need to do and all that. Then we have the workers And then all the worker threads can actually just uh process different types of requests. It could be WebSockets or it could be HTTP requests or it could be any other kind of protocol. So we want we're gonna talk about HTTP or well specifically WebSockets actually So let's dive a little bit more into it. What exactly are channels in themselves? Channels are basically just data structures that behave like a first-in, first out queue. They have message expiring and they have a policy to deliver at most one

12:47

Speaker 2: once uh to a to a listener at a time. This means that when we put a message into a channel then at most one listener is going to get that message. If something goes wrong, nobody's gonna get the message. So we need to keep this in in mind The other thing is the channels have a unique string identifier which is which makes it very easy to actually just reference one channel in different types of contexts. And the cool part is that this is network transparent, which means that it can be accessible over network, which means that we can actually have different servers communicate with each other by using Jago channels. And it also has capacity. And that means that whenever we start putting messages into a channel, they're gonna stay there until a listener comes in or a consumer that we're gonna

13:36

Speaker 2: want to wanna call it, uh a consumer comes in and grabs the message. So how do we use channels Basically, this is the way that we use channels. It's a very very basic uh function that we can use and it's something that's very like views like Django views. So and also just like Django views, we can have function views or class-based views With Jaguar Channels, we can have function consumers. This is what what our consumer function is going to look like. Or we can have class-based consumers. We're gonna give examples about about function consumers just for simplicity. So basically

14:22

Speaker 2: what it is is just a function that is gonna get a message, sorry, it's gonna get a message as a parameter and then it's going to send back that message. There's a few things that we need to to see on this example. First of all The the actual well I just created this other function here which is going to actually process the message and uh and we need to to see that every message has this dictionary that's called content So with it in inside of it, we can actually access a lot of different information. When we try to access the con the the key the the key text of it, we're actually getting the text that the the client is sending to the server. And whenever we're going to send back something through through a WebSocket channel, we need to do it in a key

15:12

Speaker 2: value. uh format because it needs to to be easily serial disabled in order to go through the through the web socket. So once once we have our response we just send it through through the through the channel Let's talk a little bit more about how to communicate back onto the client and and just to to have a more visual aspect of it. So we're we've been talking about channels, which is just a queue, a first in, first out queue, and then we have we we have the consumer functions But how the the way that they come in and come come together is that we will have a worker thread pool which will actually uh assign a thread with with one of these uh

15:58

Speaker 2: of these consumer functions to every message that comes into the channel But the the thing is that that that is how we process in this example, that is how we process a message that comes into the channel, let's say from a client. But then what about after we process it? Well if we take a look at this we are actually using this other thing on on the message object which is called reply channel So for every client that sends a message or that opens a WebSocket into the server, we're going to, well, the Django channels create a reply channel And this reply channel is just it's a it's a unique channel. It it has a unique uh string identifier and this is mapped always to just one client.

16:45

Speaker 2: So whatever we send through that is going to get sent back to the client So the only thing is that we're now talking about sending and sending stuff back to the client, but just to one client And that's not always fun because what about if we wanna wanna implement the overly used chat or something like that? Or maybe uh uh I don't know, let's say just a broadcast application, then we need to send the message different messages or well the same message to different reply channels. So we will have to to keep that in mind we will have to to keep the track of the of all of those reply channels that we need to and then look through those and all that. Luckily

17:30

Speaker 2: Luckily, uh Django channels already comes with something that's called groups. So what they do is that they keep track of a set of reply channels or regular channels. We need to to keep that in mind that that is not only for reply channels we can also make groups for I don't know maybe a cluster of servers that we want to send some information and then make them process something Uh the other thing is that they have an expiration policy because because a group is just is just a a cluster of members then whenever we put a a message in all of those in uh in all of those channels, then we need to keep track whenever those messages actually expire or else we might just keep sending messages to to expire connections. So

18:15

Speaker 2: this is basically the way that we use and that we use channels and it is very easy. Django channels, the project itself, it's actually Has actually given us all the interfaces that we need to make all of this easy. As we can see, right now I'm setting up three different consumers, consumer functions. The first one is going to fire up whenever somebody connects through a WebSocket. And what's happening here is that we're just creating this group broadcast and we're going to add the reply channel. Now this the creation of the of the group it's actually implicit here because if it doesn't exist it's just gonna create a group. If it exists it's just gonna add it to that group Then whenever we get a message, what we're doing here is that we're we're just echoing that message back to every client

19:06

Speaker 2: in that in that group. And the way that we do it is that we just use that this send function and then send it again on a on a key value format. This becomes pretty easy. And uh and we really don't don't don't need to uh to worry about anything else other than removing the the the specific member whenever the web socket actually disconnects. So the other thing is is how are we going to route all of these consumer functions Well it is pretty easy and what we do is that we set up a routing function, I mean sorry, uh a routing file which is supposed to live just right next to URLs. py And it's act it it actually looks a lot like like uh like

19:53

Speaker 2: URLs. py and this is the way that that we that we map all those consumer functions onto all those different different channels. Now one thing that that we need to to mention here is these three different channels I haven't actually explained where do those channels come from, who created those channels or where are they actually instantiated or or defined and what happens here is that Django channels also created a a spec in order to to give uh a more malleable approach to all this to to all this implementation. And what's happening here is that on the and this spec is called A SGI, as in asynchronous

20:38

Speaker 2: asynchronous SGI. And the ASGI spec tells us that whatever interface server, as as we mentioned before, whatever interface server is going to follow this spec whenever it gets a web socket connection is going to create these three different channels. So the so the so these three different channels we don't have to worry about creating them or or configuring them or anything like that, but our interface server is the one who's going to to create that. I'll talk m a little bit more about interface servers in a in a little bit. So now now that we know about replay channels the the channels that we usually have are a little bit more like this. So we have the worker thread pool and there's going to be our general channels and our response channels which those map directly to each one of the clients.

21:29

Speaker 2: And this is the the the format that the ASGI spec tells us that the response challenges is going to be, which is going to to contain this exclamation point and then anything on uh that that has to do with with uh uh these these characters. The other thing is that um how how do we oh sorry well we already mentioned how to route uh the consumer functions onto onto a specific channel. So we already talked about workers and let's just go back into our overview of Django channels. Each one of these things we're we're gonna we're gonna go through it. So we we talk about about these these different workers and we mention how to use uh to to use uh consumer functions to actually process the meshes that comes in in through a web

22:19

Speaker 2: socket. going to make all these worker threads communicate with each other because we mentioned that Django channels is is network well we can we can talk with with uh Django channels through the network so how can we actually do this And the way that we do it is that there is a channel's back-end layer. And there are out-of-the-box Django channels support different back-end layers The most basic one is memory backend and this is pretty much only good if if you're uh debugging something on your local host. because it's not it it doesn't have interprocess communication or anything like that because it's just uh it's just uh a a backend layer in in um in a piece of memory.

23:04

Speaker 2: But we can also use IPC, which is supposed shared memory segments. The benefit of this is that it's also memory, it's it's lightweight, but it also has inter-process communication. Which means that basically we can write to a different a different channel or group from outside Django from any other type of context. And the other one it's Redis. This is the the one that's that's suggested to actually use in production because it it's uh it's more robust and it also gives us the the ability to to uh configure charting and and it it this is the the the backend layer that actually works throughout network because

23:50

Speaker 2: ipc is not gonna wanna work through network or memory backend is not gonna wanna w work through the network. The way that we use some of these of these backend layers in this example this is Redis. We just install the SGI underscore Redis project I mean packet and then we put this in our settings. py as we can see this is a lot like the the database configuration and it's because it's it it they they do have some kind of a lot of similarities The same way if we want to use IPC, we're gonna have to install ASGI underscore IPC and then use the appropriate uh uh model name

24:35

Speaker 2: so that those that's that's basically how we how we we We configure a channel backend and the way that we use it is that whenever we write onto a group or we write into a channel, we're actually writing onto this this uh backend layer And now what about the interface layers? I mean the interface servers. So what happens with the interface servers is that Django channels actually already ships with an interface server that's called Daphne. And this interface server what it does is that it's based on on Twisted because Twisted already gives us an implementation of WebSockets and an HTTP long polling too uh and so Daphne is just using these implementations in order to to keep to to the ASEI spec

25:24

Speaker 2: What we can do is that we can we can use Daphne as our sole interface, interface server, and and Daphne can actually have knows how to handle different requests like HTTP, regular HTTP requests. or WebSocket request that is going to route them the way that we want it to. Now the only thing is that Daphne is pretty new and maybe we don't want to do that on production. But we can also run Whiskey and Daphne side by side. So the only thing is that we're gonna have engine something like Nginx to actually load balance different requests. So the HTTP requests, they're gonna go through our regular WISGI server and the WebSocket messages are gonna go through Daphne. So basically the way that we're going to

26:10

Speaker 2: to set up our interface server because our interface server is really just just another another server like like a whiskey server we're going to create an ASGI. py uh file and we're going to put this into it and the only thing that that we're doing here is that we are actually getting the channel layer which is the one that we configure here. As you can see this one is called channel layers and we're we this this one is the the default one We can have multiple channel layers too if we want to, if our application is very convoluted and maybe there is a lot of different types of servers in the back end talking to each other, etc. Or maybe we just want to separate our our channel layers by concerns.

27:00

Speaker 2: So and and the way that we run Daphne it's basically just doing this. Daphne is the command and then we just give it give it this this uh the model the module as as a as a parameter Pretty much the same way that we that we run Whiskey. So that's uh the interface server. Now what about uh well we talk about about how Django channels are actually work throughout the the the the network right so what about if how can we can we use channels from somewhere else outside Django So the only thing that that we can uh well the thing that we need to keep in mind is that we don't need to be in a specific content to write to a channel. We just not to we just need to have access to the channel backend layer

27:47

Speaker 2: And uh and and the way that we do it is just using the same things that that we've already seen, which is just If we already have the the name or the string of the of the group, we can just send that to we we can just use this interface to actually write to that group and every member of that group is gonna get that that message If we want to send it to a specific client, we can actually just use the reply channel. Now the reply channel again it's only a string. So if we dive into into the Django channels, uh Can everybody see that? If if we if we dive into into the Django channels uh code, we can see that a message actually has a the The way that that they create the

28:33

Speaker 2: reply channel is just instantiating a channel object with the reply channel string and then just the channel layer. Now we don't necessarily need to know which channel layer we're gonna use if we only have one because it's always gonna default to the default one But if we got if we have multiple ones, the way that we do it is that we can actually use use just a string that's going to be the alias of it. And the alias of it we've already configured it here. This for instance the alias is default. If we add another one, the alias is going to be, I don't know, maybe uh uh image processing or something like that.

29:18

Speaker 2: So let's continue with this. Okay. Well and now uh since we still have time that was a little bit quicker than I expected Uh I'm gonna show you real quick how we can write to to a uh to a Django channel actually outside from Django because I think this is this is one example that leverages on on all on every every aspect of of Django channels So basically what I did here, I'm just running Django. It's it's a very vanilla installation of Django and I'm just running it using uh run server. So after installing channels We can see that when we run when when we run this, we're gonna have all this information about the workers.

30:07

Speaker 2: Now what's happening here is that actually the workers are are being executed in the same in the same thread as the as the run server and this is just because it's for debugging. If we were in production, what we needed to do is to actually run the the Whiskey server and then run Dapn on another process and then run the the the swarm of of of worker threads. So now we know that we're listening on all these different channels. HTTP request is another channel that the ASGI spec tells us. that the interface server is going to create whenever an HTTP request comes in. So if we go into the client Let's delete this. Basically, the way that we do it

30:54

Speaker 2: is that we create a web socket like this. Web sockets uh the the support for web sockets are in actually most of the major browsers and we don't we can we can just open a web socket like this is it's pretty easy. Once we created it we get all this information back Now if we take a look at this, I have here what I'm doing is that I'm actually printing different information that we can get from a web socket. So as we can see here the reply channel, it's just this string. We can see that it has this exclamation point here. So if we set let we're gonna set this this function, what what it's going to do is that whenever we get a message on the client, it's just going to

31:45

Speaker 2: is is just going to uh print it to the to the console. So right now what our what our backend is is doing or what what our server is doing is just doing a a an echo on the on the message. itself. So if we send something, we're gonna get back the same thing, right? So what about writing something onto onto a channel from anywhere else? So because we just open a channel, we now have here, obviously on a on a on a better project, uh where we will save this string On a model or something like that, but we can copy this string and here I'm just on the same virtual machine and we're going to send it using

32:33

Speaker 2: this using this this um Django command. I'm gonna go through the Django command in a in a in a little bit. So basically what it's doing is that I'm just giving it a string which is the the channel ID and I'm just giving it a message to send which right here is just message underscore send So once I send it, we can see that we got it here. So now we're we're actually writing on to Django from outside Django just from the console And what we can I mean we can do whatever we want with this actually we can just set up a a machine um monitoring system to to be sending messages to our phones or whatever. So now let's take a look at

33:21

Speaker 2: at the at the command. Basically this is just this is the command that that I just use. And what it does is that it just grabs the channel ID and then the message and it creates the channel like that It just instantiates the channel and then it just uses the same function to send the message back to the client and then the client is gonna is gonna get it. Now The other interesting part about this is the way that we're echoing back the the uh The the message and let me sorry. Let me take a look at it.

34:06

Speaker 2: Yeah. So this this is our uh this these are our three different consumer functions. So as we can see on the We're gonna have this WS underscore connect function and what it does is that it only tries to print out the user, but because we don't have any kind of of uh of authentication is going to print an empty string. If you see here it's just printing an empty string. But this is pretty interesting because the other cool thing about Django channels is that it comes already with different types of um of decorators that gives us access to to the to the user object and to the user session. That way we can we can use authentication or we can just check which user is sending the message and routes accordingly

34:52

Speaker 2: or maybe we can just put something on the on the user session. Now the important thing to note here is that we're going to use This this this decorator whenever a user connects because whenever a user connects is when first is going to send the HTTP packet And then after that, any consequent messages that goes through through the WebSocket, it doesn't actually has any other type of information that that a regular HTTP request is gonna have, like cookies or session or all that So when we use this, Django channels actually saves all of that data. And then when we want to use it again on a message, we use this other

35:37

Speaker 2: decorator, which will then give us access to the session. So here the only thing that that we're doing is just sending it back to the user That this is a pretty basic example. I'll be uploading actually a more convoluted example or more complete example afterwards just didn't want to to go through a lot of lines of coda at the same time that as the talk. So um Any questions? Yeah.

36:07

Speaker 3: Hi. Um what I was curious about, uh what you described um using kind of the hybrid whiskey um um ASCII model is you're essentially running two copies of the application, correct? I mean the ASGI um works similarly to how you know the Guna Corona URUSGI does today with where it essentially is the loader for your application.

36:29

Speaker 2: Yeah.

36:30

Speaker 3: Okay, so you're basically so there's going to be some implications there then for uh You know, like how you would size an instance uh for running that sort of model then?

36:40

Speaker 2: Well actually what uh what uh what the whole model what what it does is that it's going to to just If you if we take a look at how we're running our interface server, this is the only thing that we're that we're giving it. We're only giving it the channel layer. So it's I think what what you're saying is that is that then the the interface server is actually running another Django instance and all that. But actually what it's doing is that Is that whenever a message comes in, it's just going to fire up or well it's going to put it in the channel and then a worker thread is gonna get that channel and it's just gonna fire up that consumer function And then the consumer function is just gonna put it back there and is it's gonna come back into it. And because Django channels is just everything inside Django, then we can we can still use things

37:26

Speaker 2: that that we still use in Django like models or any other things. But it's not actually just firing up another instance or or another thread of Django. It's just those those things.

37:39

Speaker 3: Okay, and then uh the communication then between the WISGI side of things and the ASCII side of things, that would be via the back-end message.

37:46

Speaker 2: Yeah, via via the backend layer.

37:48

Speaker 3: So you would not be able to use use uh that kind of hybrid model uh with a memory only backend you would have to use at least IPC.

37:56

Speaker 2: Well you you can you can use it yeah with IPC. The only the only thing with with IPC is that you cannot use it through the network.

38:01

Speaker 3: Right, right. Yeah. Okay thank you

38:05

Speaker 4: Thank you very much. Can we talk about how to do this? So my question for you is, like obviously you've done a lot of experimenting with channels, what do you think is the most thing that's missing most from channels?

38:16

Speaker 2: That is missing most?

38:17

Speaker 4: Yeah. But what what do you want?

38:19

Speaker 2: Ah that's a that's a pretty uh interesting idea. But I think the the the things that that are missing uh a little bit maybe is just uh some something on top of the of the current interfaces that it already has uh to make it a little bit more more easier for instance to to send a a message to a to a channel from outside Django but but to a specific user. I mean it's it's pretty pretty easy to do it with with groups But let's say that I I want but that I have two servers, right? And then one server is just just the front and it just handles requests for the front end and then the other one it does some kind of of heavy heavy uh processing like machine learning processing or something like that. So then the first error I I would like to use Django channels to actually have these two communicate with themselves.

39:08

Speaker 2: So then on the first error I want to to send that information through the channel. and then on the or or through a a group maybe and then on the on the other server I would like to send that just to that specific reply channel. So just getting a hang on the on that reply channel it's sometimes gets a little bit convoluted Okay.

39:25

Speaker 4: Thank you. Thank you.

39:29

Speaker 5: Oh, yes. Hi. Um I was wondering, and maybe I you may have just kind of explained it, um, but between the persistent um The interface server and the channel layer. How do you handle persistence if you were going to have multiple servers? Like at what point like so if each channel is going to a client and the client comes back in through your load balancing situation and ends up in a different place over here, how do you make sure that they're Still on a channel. Like you do that in your load balancing or

40:02

Speaker 2: Okay, let me see if if I uh if I got that question correct. Uh and And what happens here is because of of the of the backend layer. If we use something like Redis, then it's gonna go through through the network. So whenever a message comes in then that is going to to go to a channel that's that's gonna be called let's uh as we saw websocket. message, right? I mean sorry, I think it's it was received. So when it goes through that channel, actually anybody that has access to Redis it's gonna be able to to read that that channel and yeah with channels is gonna go like okay somebody needs to to take care of this message it's gonna tell that to the worker thread pool The worker thread pool is gonna grab that. Now we're gonna have different worker thread pools trying to grab that message. But uh one is is one one of those threads is is the only one who's gonna grab that message

40:48

Speaker 2: And then the other one's gonna go like, alright, that this this was already taken care of. Now when going back, that's why we have the reply channels, which are unique per client So whenever you put there, the only thing nobody else is going to get that message on unless that that one client. Hence why Django channels, the policy of Django channels is to deliver at most once to to one listener or any kind of message. Instead instead of deliverable to too many.

41:14

Speaker 5: Thank you.

41:14

Speaker 2: No problem. So

41:16

Speaker 6: to clarify that, Redis handles the incoming, but it doesn't it doesn't notify in terms of outgoing is what you're saying. Like like because right now that in a normal way of doing it, that's what we'll do now, like income the Redis, Redis would signal, right? And then once they're done processing, it would signal back to Redis and then and then update everybody right

41:35

Speaker 2: yeah

41:35

Speaker 6: that's true but that but now with with Django channels that's not true or is that still true uh

41:41

Speaker 2: wait uh I got a little bit confused there so you mean that that when going back when when sending back to to the to the client Well actually yes because the one that sends back to the client it's also a worker thread. So something because because uh we need to remember that a reply channel is just that, it's another channel The only thing is that it has a unique string so that way we're not gonna have uh different members on that on that one channel. Uh this is just gonna gonna gonna have one one one client So whenever we need to reply something, we put that we we put that message into that channel and then Redis is gonna is gonna go like hey I have something new for somebody. The work through is uh somebody's gonna go and grab it and with that with with that unique channel Jago child is know how to actually route it back to the client.

42:29

Speaker 2: It's gonna go like okay, there you go.

42:32

Speaker 6: All right, thank you. One final question

42:36

Speaker 2: Oh, sorry. Um

42:38

Speaker 7: so have you played with celery

42:39

Speaker 2: at all? Yeah. Um that's cool.

42:45

Speaker 7: uh a lot of the naming conventions that I see using like groups, channels, that kind of stuff, I see it a lot in terms of just like celery implementing AMQP pieces. Do you see yourself trying to push for like persistent message protocol or like website message protocol like in Django because it could it could grow out to include topics and fan outs and I can see that kind of stuff happening. So I was curious as to where you saw it going.

43:14

Speaker 2: Yeah, well actually uh the only thing is that Django Channels is it's it it kind of resembles uh uh an AMPQ, but it's really not that What it's trying to do is it's just trying to give us a an abstraction layer for us to actually use something like that. So all of that is really not gonna is Jamma Challenge is not gonna try to put them together. It's not gonna try to clash on that. But for instance, what what what I've been using it for is that I I still use use uh celery. So whenever a request comes in from let's say a user pushes a button or something like that or click clicks a button and then the salary task will start and whenever whenever the salary task needs to say something to the to the client it will just write something to that channel. But that's that's that's all the the involvement of Jan with channels.

43:59

Speaker 2: Thank you. Cool. So uh if you have any other questions, these are the ways that you can contact me. My email, my Twitter, it's a little bit weird. And I'm always on IRC. Special thanks to everybody, people at Django, and these guys too. Thank you

Questions this talk answers

Why use WebSockets instead of regular HTTP?

WebSockets keep a persistent TCP connection open so the client and server can send messages at any time, reducing request-response latency and enabling real-time applications.

Discussed at 1:02

Why can't regular WSGI handle WebSockets efficiently?

WSGI is built around a request-response workflow and typically occupies a thread while processing a request. Keeping that thread alive indefinitely for a WebSocket connection is not scalable, so WebSocket applications use offloading, asynchronous libraries, or separate interface and worker processes.

Discussed at 2:33

Why was Django Channels created?

Django Channels provides a Django-native, extensible way to handle WebSockets and asynchronous work. It abstracts much of the thread offloading and async management that would otherwise have to be assembled from separate services or frameworks.

Discussed at 9:38

What is a channel in Django Channels?

A channel is a network-transparent, first-in-first-out queue with expiring messages, a capacity, and a unique string identifier. A message is delivered to at most one listener, which allows workers to coordinate across processes or servers.

Discussed at 11:58

How do you broadcast a WebSocket message to multiple clients with Django Channels?

Use a group to track multiple reply channels or regular channels, then send the message to the group. Django Channels handles delivering the message to the group members and expiring stale connections.

Discussed at 17:30

How do you configure Django Channels for production?

Use a channel backend such as Redis, which supports interprocess and network communication and is recommended for production. Daphne can serve ASGI traffic, either alone or alongside a WSGI server behind a proxy such as Nginx.

Discussed at 23:04

How can code outside Django send a message to a Django Channels client?

It only needs access to the configured channel backend and the target channel or group name. Code such as a management command can instantiate the channel and send a message, which the worker then routes to the client.

Discussed at 27:00

How does Django Channels preserve authentication and session data over a WebSocket?

Authentication and session information is captured when the user initially connects over HTTP. Django Channels provides decorators that expose the user and session to later WebSocket messages, even though those messages no longer carry normal HTTP cookies and session data.

Discussed at 34:06

Note: We understand that names change, people change, and bodies change. We respect each individual's journey and privacy. If you have any concerns about a video or need us to remove content, please don't hesitate to contact us. We will handle your request with care and promptly address any issues.

More videos by Josue Balandrano Coronel

More videos from DjangoCon US