WebSockets: Intro to Messaging
This is a modal window.
The media could not be loaded, either because the server or network failed or because the format is not supported.
Formal Metadata
Title |
| |
Title of Series | ||
Part Number | 17 | |
Number of Parts | 52 | |
Author | ||
License | CC Attribution - ShareAlike 3.0 Unported: You are free to use, adapt and copy, distribute and transmit the work or content in adapted or unchanged form for any legal and non-commercial purpose as long as the work is attributed to the author in the manner specified by the author or licensor and the work or content is shared also in adapted form only under the conditions of this | |
Identifiers | 10.5446/32728 (DOI) | |
Publisher | ||
Release Date | ||
Language |
Content Metadata
Subject Area | ||
Genre | ||
Abstract |
|
DjangoCon US 201617 / 52
6
10
13
14
17
20
23
31
36
44
46
47
48
49
00:00
Figurate numberSoftware frameworkEvent horizonWeb pageVariable (mathematics)Cartesian coordinate systemContext awarenessDebuggerTask (computing)Thread (computing)PhysicalismDifferent (Kate Ryan album)HTTP cookieOverhead (computing)TelecommunicationLibrary (computing)Message passingInformationMultiplication signConnected spaceMereologyDependent and independent variablesRegular graphInterface (computing)Server (computing)Order (biology)LastteilungWeb applicationRepresentational state transferClient (computing)Loop (music)Frame problemProjective planeFormal languageEmailRight angleData dictionaryProgramming paradigmSemiconductor memoryChannel capacityData storage deviceProcess (computing)Point (geometry)Communications protocolProduct (business)Digital electronicsWeb 2.0Power (physics)Constraint (mathematics)Endliche ModelltheorieGenderRule of inferenceArithmetic progressionClique problemSubject indexingInsertion lossDirection (geometry)ResultantWorkstation <Musikinstrument>WebsiteFront and back endsWhiteboardReal-time operating systemBitSource codeAuditory maskingPlastikkarteTwitterMassCircleAtomic numberParallel portLogical constantAreaGroup actionMeasurementAnalogyComputer animation
09:14
Type theoryMereologyContext awarenessFunctional (mathematics)IdentifiabilityDemosceneDigital electronicsServer (computing)Broadcasting (networking)View (database)Social classSoftwareMessage passingArithmetic meanInformationOrder (biology)Cartesian coordinate systemData structureDifferent (Kate Ryan album)Computer architectureString (computer science)Thread (computing)Uniqueness quantificationMultiplication signObject (grammar)Web 2.0Food energyMeasurementProcess (computing)Classical physicsProduct (business)Interface (computing)Error messageParticle systemConnected spaceBitInformation overloadEntire functionEndliche ModelltheorieProxy serverDisk read-and-write headGenderAngleTrailRight angleLibrary (computing)Source codeSet (mathematics)Group actionNichtlineares GleichungssystemParameter (computer programming)WebsiteDependent and independent variablesClient (computing)Medical imagingFirewall (computing)Regular graphProjective planeQueue (abstract data type)Communications protocolScripting languageComputer animation
18:13
Functional (mathematics)GenderMeasurementWeb browserSemiconductor memoryProduct (business)Link (knot theory)Spring (hydrology)Interface (computing)Message passingThread (computing)WebsiteStandard deviationSoftwareDifferent (Kate Ryan album)Computer fileInternational Date LineCartesian coordinate systemMultiplicationBitDependent and independent variablesRoutingLevel (video gaming)Web 2.0ImplementationFile formatClient (computing)Point (geometry)Regular graphError messageDigital electronicsACIDSeries (mathematics)Set (mathematics)Server (computing)Bit rateSpacetimeGroup actionConnected spaceConfiguration spaceDatabaseInterprozesskommunikationSimilarity (geometry)Term (mathematics)Context awarenessType theoryRegulator geneWeightSpeciesRight angleGradientLastteilungOrder (biology)Module (mathematics)Endliche ModelltheorieParameter (computer programming)Socket-SchnittstelleNetwork socketShared memoryFront and back endsUniform resource locatorPolygon meshProjective planeComputer animation
27:11
Thread (computing)Multiplication signInterface (computing)Line (geometry)CodeRegular graphHTTP cookieType theoryNetwork socketSocket-SchnittstelleWeb 2.0Server (computing)Object (grammar)String (computer science)Different (Kate Ryan album)Functional (mathematics)AliasingBitDefault (computer science)Message passingRoutingVirtual machinePhysical systemGroup actionFront and back endsContent (media)MereologyPoint (geometry)Image processingClient (computing)InformationRight angleEndliche ModelltheorieVideo game consoleBranch (computer science)WebsiteChemical equationDigital electronicsACIDSummierbarkeitAssociative propertySheaf (mathematics)Computer programmingJava applet1 (number)Order (biology)Spring (hydrology)PRINCE2GenderWordNumberProcess (computing)Form (programming)Network topologyProjective planeSurjective functionSoftwareXMLComputer animation
36:10
Server (computing)Instance (computer science)Endliche ModelltheorieTelecommunicationFormal grammarFunctional (mathematics)SoftwareGenderCartesian coordinate systemSet (mathematics)QuicksortSemiconductor memoryASCIIMessage passingThread (computing)Interface (computing)Front and back endsHybrid computerBootingRight angleComputer animation
38:17
Thread (computing)Web 2.0Network socketSoftwareMessage passingStructural loadDifferent (Kate Ryan album)Group actionLatent heatVirtual machineProcess (computing)BitMultiplicationConvolutionInterface (computing)Server (computing)Term (mathematics)InformationTask (computing)Communications protocolAbstractionFront and back endsClient (computing)Inclusion mapWebsiteUniqueness quantification1 (number)RoutingEmailRadiusOrder (biology)LastteilungRandom measureRight angleMeasurementGamma functionOnlinecommunityInstance (computer science)Hand fanState of matterCore dumpTwitterDemosceneCellular automatonPosition operatorString (computer science)Water vaporPoint (geometry)BuildingSocial classSimilarity (geometry)
44:20
Computer animationJSONXML
Transcript: English(auto-generated)
00:00
Come on! Thank you. Good afternoon. So today is going to be a day of firsts, because this is my first DjangoCon.
00:20
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 wore this jacket. So let's start. Why WebSockets? Why talk about WebSockets? Well, the thing is that actually web applications have been growing more and more every year.
00:40
And now we have way more robust applications, not only 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 server more regularly. As well as the server, we're now processing more data on the server. So what this happens is that with our regular HTTP
01:03
part of the request response, there's a lot of latency in this communication. And in order to solve this, well, we created the WebSocket specs. And basically what WebSockets is, the idea behind WebSockets is to have a persistent connection between the client and the server.
01:22
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,
01:42
which is the HTTP just opens a connection, sends a request, then the server processes the request, sends the response back, and it closes the connection. While on WebSockets, the channel is always open. All is the client closes it, or the server decides to close the connection. So let's take a quick look at the WebSockets spec,
02:04
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 persistent connection. And also the way to start a WebSocket or to open a WebSocket is to send an HTTP request, but it has an upgrade header on it.
02:21
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 on the server side? What's happening? Because that's what we're here for. So let's take a look at a WebSocket server under the hood.
02:41
I'm not gonna go into much detail, but just the overall overview. So the first thing that we need to keep in mind is that WebSockets cannot be handled by regular WSGI workflow, because if we take a look at the WSGI workflow, it is pretty much based on the regular HTTP request response paradigm. So whenever a client sends a request,
03:00
the server processes it, and when the server is processing the request, we have this workflow right here, which is, the packet is probably gonna go through an HTTP server, like Apache or Nginx, and then it's gonna go to the WSGI server, which will then send all the information with header and a WSGI dictionary to Django. Django is going to process all that data
03:21
and create the response, and then it will send it back to the client, and the connection is gonna be closed. Now, when this is happening here, when everything happens through the WSGI server, and then Django gets called and all that, that's happening on a thread. So if we would like to keep this same workflow
03:41
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.
04:02
So one of the solutions, actually, is a concept that's called offloading. And offloading is using one or more threads to handle slower-loading running tasks, which can be managed in a non-blocking way. We can see that now our workflow changes a little bit.
04:20
Usually in production, what we see with WebSockets is that a lot of people just run two different WSGI 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 messages. So now, here's where things get interesting, because when a WebSocket message comes in,
04:41
what's happening is that the WSGI server actually fires up a worker thread, which will then process the request. This is going to free the WSGI server to be able to handle any other concurrent requests that are gonna come into WebSocket messages. So this is an improvement on the whole workflow.
05:02
But the thing here is that now we're starting to talk about direct threads. We're talking about using threads to process 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,
05:21
something like J event or async IO. There's a lot of different libraries like this in Python. Now, the issue with this is that there's a lot of things that we need to keep in mind, and there's a lot of caveats just when we start diving into the whole asynchronous topic and thread managing.
05:43
So first of all, let's mention that uploading is not a new concept, and other frameworks are using it, like Node.js or maybe Go, too. We are diving into the async world, and as I was mentioning, this has a lot of different issues. There's a lot of different issues that can make us actually shoot ourselves
06:02
on the foot very easily, and we need to figure out also how to make these threads to communicate with each other in order to persist the data, let's say the session data or cookies data or things like that, because every thread
06:20
that we fire up is gonna be working on it or is gonna be processing things on a different context, so we can't just put data on global variables and expect all the threads to know about those variables. But the cool thing is that by using this new workflow, now our application is event-based.
06:41
Now 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.
07:01
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. The whole point of this talk is to talk about Django channels,
07:20
but I'm gonna talk about other projects that try to actually do this, just to see where those Django channels actually come from and what is Django channels, it's actually trying to solve. The first solution that people came up with is to use just another entire complete different service to handle WebSockets like Node.js,
07:41
and this is going to change our workflow a little bit, and it will be something like this. We can still use our HTTP server 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
08:00
into different languages on the server, 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. This is still putting a lot of different overhead on the whole communication of this.
08:22
Nevertheless, it is a solution that people use out there, so the other thing is that these are just two different technologies which can be hard to maintain sometimes, and it's really not Django native. It's more of a kind of hack, although it works. The other thing is that we can just use
08:41
another Python asynchronous event framework like Twister or Kornado. So the idea is basically the same one a little bit, since we'll be running Django in parallel with this other asynchronous event framework, and then we can make those two talk with each other. The other thing is to use whiskey offloading
09:03
and a way to actually make the threads to talk to themselves so that way we don't fall into the different issues that come with different thread contexts is to use storage backing like Redis or something like that that every thread can actually read and write to.
09:22
So if we already have all these different solutions, why talk about Django channels? Why is Django channels tried 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. These are just things that you're running
09:41
probably with Django, and what we love and like and we want to develop on is Django. The other thing is that 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 any way that we want it,
10:04
maybe use a different library, maybe just modify a library in some way or another, or something like that. The other thing is that Django channels is trying to abstract the async handling of the entire offloading of the threads. That way we don't have to worry that much about it,
10:23
and we don't shoot ourselves in the foot that much. The other thing is that also Django has always been very friendly with other technologies, and it's very easy to just maybe run a script outside Django or something like that and make it talk to Django, and Django will actually
10:43
do a lot of pretty cool things with this. Let's just overview, again, the way that we can actually implement offloading with WSGI because this is one of the things that approaches more the model of Django channels.
11:02
As we remember, we have two WSGI servers, which one of them is going to be handling the WebSocket connections and then firewall worker threads. If we take a look at how Django channels actually works, we can see that this is a little bit like it, not necessarily the same,
11:21
but the idea behind it is the same one. Whenever we have a packet come in, we're gonna have an interface server because the processing of all the requests or messages are going to happen on the worker threads, then our WSGI server or HTTP server
11:41
actually becomes only an interface server, which is a layer between our Django project and the wild out there. Then after this, we have a channel backing, which is the new thing that we're gonna talk about. This is going to let us actually control
12:02
the different information that all these worker threads are going to need in order to know when they're gonna fire off and what do they need to do and all that. Then we have the workers. All the worker threads can actually just process different types of requests. It could be WebSockets or it could be HTTP requests
12:21
or it could be any other kind of protocols. We're gonna talk about HTTP, well, specifically WebSockets, actually. Let's dive a little bit more into it. What exactly are channels themselves? Channels are basically just data structures that became like a first in, first out queue.
12:41
They have message expiring and they have a policy to deliver at most one to a listener at a time. This means that when we put a message into a channel, then at the most, one listener is going to get that message. If something goes wrong, nobody's gonna get the message.
13:01
We need to keep this in mind. The other thing is that channels have a unique string identifier, which makes it very easy to actually just reference one channel in different types of contexts. 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
13:22
communicate with each other by using Django channels. It also has capacity. 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 call it, a consumer comes in and grabs the message.
13:42
How do we use channels? Basically, this is the way that we use channels. It's a very, very basic function that we can use, and it's something that's very like views, like Django views.
14:01
Also, just like Django views, we can have function views or class-based views. With Django channels, we can have function consumers. This is what our consumer function is gonna look like, or we can have class-based consumers. We're gonna give examples of function consumers just for simplicity.
14:22
Basically, what it is is just a function that is 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 see on this example. First of all, I just created this other function here
14:41
which is going to actually process the message, and we need to see that every message has this dictionary that's called content. So inside of it, we can actually access a lot of different information. When we try to access the key text of it,
15:01
we're actually getting the text that the client is sending to the server. And whenever we're going to send back something through a WebSocket channel, we need to do it in a key-value format, because it needs to be easily serialized able in order to go through the WebSocket.
15:20
So once we have our response, we just send it through the channel. Let's talk a little bit more about how to communicate back onto the client, and just to have a more visual aspect of it. So we've been talking about channels, which is just a queue, a first-in, first-out queue,
15:40
and then we have the consumer functions. But the way that they come together is that we will have a worker thread pool which will actually assign a thread with one of these consumer functions to every message that comes into the channel.
16:05
But the thing is 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're actually using this other thing
16:21
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, the Django channels create a reply channel. And this reply channel, it's a unique channel. It has a unique string identifier
16:42
and this is mapped always to just one client. 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 stuff back to the client but just to one client. And that's not always fun because what about if we wanna implement the overly-used chat
17:04
or something like that? Or maybe, I don't know, let's say just a broadcast application. Then we need to send the different messages or the same message to different reply channels. So we will have to keep that in mind.
17:20
We will have to keep track of all of those reply channels that we need to and then look through those and all that. Luckily, 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 keep that in mind.
17:40
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. The other thing is that they have an expiration policy because a group is just a cluster of members. Then whenever we put a message in all of those channels,
18:05
then we need to keep track whenever those messages actually expire, or else we might just keep sending messages to expired connections. This is basically the way that we use channels, and it is very easy.
18:21
Django channels, the project itself, 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 consumer functions. The first one is going to fire up whenever somebody connects through a web socket.
18:42
What's happening here is that we're just creating this group broadcast, and we're going to add the reply channel. Now, the creation 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
19:02
is that we're just echoing that message back to every client in that group, and the way that we do it is that we just use this send function, and then send it, again, on a key value format. This becomes pretty easy, and we really don't need to worry about anything else other than removing
19:24
the specific member whenever the web socket actually disconnects. The other thing 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 file, which is supposed
19:45
to live just right next to urls.py, and it actually looks a lot like urls.py, and this is the way that we map all those consumer functions onto
20:01
all those different channels. Now, one thing that we need 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 they actually instantiated or defined, and what happens here is that Django channels
20:24
also created a spec in order to give a more malleable approach to all this implementation, and what's happening here is that this spec is called asgi, as in asynchronous asgi,
20:40
and the asgi spec tells us that whatever interface server, as we mentioned before, whatever interface server is going to follow this spec, whenever it gets a web socket connection, it's going to create these three different channels. So these three different channels, we don't have to worry about creating them
21:01
or configuring them or anything like that, but our interface server is the one who's going to create that. I'll talk a little bit more about interface servers in a little bit. So now that we know about replay channels, the channels that we usually have are a little bit more like this. So we have the worker thread pool,
21:21
and there's going to be our general channels and our response channels, which those map directly to each one of the clients, and this is the format that the asgi spec tells us that the response channels is going to be, which is going to contain this exclamation point and then anything that has to do with these characters.
21:46
The other thing is that, how do we, oh, sorry, we already mentioned how to route the consumer functions onto a specific channel. So we already talk about workers,
22:00
and let's just go back into our overview of Django channels. Each one of these things, we're gonna go through it. So we talk about these different workers, and we mention how to use consumer functions to actually process the meshes that comes in through a web socket.
22:21
The next thing is that, how are we going to make all these worker threads communicate with each other? Because we mentioned that Django channels is network, well, we can talk with Django channels through the network, so how can we actually do this? And the way that we do it is that there is a channels backend layer.
22:42
And there are, out of the box, Django channels support different backend layers. The most basic one is memory backend, and this is pretty much only good if you're debugging something on your local host, because it doesn't have inter-process communication or anything like that, because it's just
23:00
a backend layer in a piece of memory. But we can also use IPC, which is supposed to share memory segments. The benefit of this is that it's also memory, it's lightweight, but it also has inter-process communication, which means that basically we can write
23:20
to a different channel or group from outside Django or from any other type of context. And the other one, it's Redis. This is the one that's suggested to actually use in production, because it's more robust, and it also gives us the ability to configure sharding.
23:45
This is the backend layer that actually works throughout network, because IPC's not gonna work through network, or memory backend is not gonna work through the network. The way that we use some of these backend layers, in this example, this is Redis.
24:01
We just install the ASGI 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 database configuration, and it's because they do have a lot of similarities.
24:22
The same way, if we want to use IPC, we're gonna have to install ASGI underscore IPC, and then use the appropriate model name. That's basically how we configure a channel backend,
24:43
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 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
25:02
with an interface server that's called Daphne. And this interface server, what it does is that it's based on Twisted, because Twisted already gives us an implementation of web sockets and HTTP long polling too. So, Daphne is just using these implementations in order to keep to the ASGI spec.
25:24
What we can do is that we can use Daphne as our sole interface server, and Daphne knows how to handle different requests, like HTTP, regular HTTP requests, or a web socket request that is going to route them the way that we want it to.
25:41
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 WSGI and Daphne side by side. So, the only thing is that we're gonna have something like Nginx to actually load balance different requests. So, the HTTP request, they're gonna go through our regular WSGI server, and the web socket messages
26:04
are gonna go through Daphne. So, basically, the way that we're going to set up our interface server, because our interface server is really just another server like a WSGI server, we're going to create an asgi.py file,
26:24
and we're going to put this into it. And the only thing 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 this one is the default one.
26:41
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 backend talking to each other, et cetera. Or maybe we just want to separate our channel layers by concerns.
27:00
So, 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 the module as a parameter. Pretty much the same way that we run WSGI. So that's the interface server. Now, what about, well, we talk about how Django channels
27:23
are actually work throughout the network, right? So what about, how can we use channels from somewhere else outside Django? So the only thing that we can, well, the thing that we need to keep in mind is that we don't need to be in a specific content
27:42
to write to a channel. We just need to have access to the channel backend layer. And the way that we do it is just using the same things that we've already seen, which is just, if we already have the name or the string of the group, we can just send that to,
28:02
we can just use this interface to actually write to that group, and every member of that group is gonna get 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 the Django channels,
28:22
can everybody see that? If we dive into the Django channels code, we can see that a message actually has, the way that they create the reply channel is just instantiating a channel object with the reply channel string
28:41
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 have multiple ones, the way that we do it is that we can actually use a string that's going to be the alias of it.
29:03
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 image processing or something like that. So let's continue with this.
29:23
Well, now, since we still have time, that was a little bit quicker than I expected, I'm gonna show you real quick how we can write to a Django channel actually outside from Django,
29:42
because I think this is one example that leverages on every aspect of Django channels. So basically what I did here, I'm just running Django. It's a very vanilla installation of Django, and I'm just running it using run server. So after installing channels,
30:02
we can see that when we run this, we're gonna have all this information about the workers. Now, what's happening here is that actually workers are being executed in the same thread 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 WSGI server
30:22
and then run that in another process, and then run the swarm 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
30:40
whenever an HTTP request comes in. So if we go into the client, just delete this, basically the way that we do it is that we create a web socket like this. Web sockets, the support for web sockets are in actually most of the major browsers,
31:06
and we can just open a web socket like this. 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
31:22
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're gonna set this function, what it's going to do is that
31:41
whenever we get a message on the client, it's just going to print it to the console. So right now, what our backend is doing or what our server is doing is just doing an echo on the message itself.
32:00
So we send something, we're gonna get back the same thing, right? So what about writing something onto a channel from anywhere else? So because we just opened a channel, we now have here, obviously on a better project, where we will save this string
32:22
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 this Django command. I'm gonna go through the Django command in a little bit.
32:40
So basically what it's doing is that I'm just giving it a string, which is 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 actually writing onto Django
33:01
from outside Django, just from the console, and we can do whatever we want with this. Actually, we can just set up a machine monitoring system to be sending messages to our phones or whatever. So now let's take a look at the command.
33:23
Basically, this is the command that I just used, and what it does is 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 send function to send the message back to the client,
33:41
and then the client is gonna get it. Now, the other interesting part about this is the way that we're echoing back the message.
34:01
Let me, sorry, let me take a look at it, yeah. So this is our three different consumer functions. So as we can see, we're gonna have this ws underscore connect function. What it does is it only tries to print out the user,
34:22
but because we don't have any kind of authentication, it's 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, the only chance is that it comes already with different types of decorators that gives us access to the user object
34:43
and to the user session. That way, we can use authentication, or we can just check which user is sending the message and route accordingly, or maybe we can just put something on the user session. Now, the important thing to note here is that we're going to use this decorator
35:06
whenever a user connects, because whenever a user connects is when first it's going to send the HTTP packet, and then after that, any consequent messages that go through the web socket, it doesn't actually have any other type of information
35:22
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 wanna use it again on a message, we use this other decorator, which will then give us access to the session.
35:42
So here, the only thing that we're doing is just sending it back to the user. This is a pretty basic example. I'll be uploading actually a more convoluted example or a more complete example afterwards, just didn't want to go through a lot of lines of code
36:01
at the same time as the talk. So any questions? Yeah. Hi. What I was curious about, what you described using kind of the hybrid, WSGI, ASCII model, is you're essentially running two copies of the application, correct? I mean, the ASCII works similarly to how,
36:23
Gunnar Korn or you, WSGI does today, with where it essentially is the loader for your application? Okay, so you're basically, there's going to be some implications there then for how you would size an instance for running that sort of model then.
36:40
Well, actually, what the whole model, what it does is that it's going to just, if we take a look at how we're running our interface server, this is the only thing that we're giving it. We're only giving it the channel layer. So I think what you're saying is that then the interface server is actually running
37:01
another Django instance and all that, but actually what it's doing 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 that consumer function is just gonna put it back there and it's gonna come back into it,
37:21
and because Django channels is just everything inside Django, then we can still use things that we're still using Django, like models or any other things, but it's not actually just firing up another instance or another thread of Django. The only thing that we're giving it there is just, it's just those things.
37:40
Okay, and then the communication then between the WSGI side of things and the ASCII side of things, that would be via the backend message? Yeah, via the backend layer. So you would not be able to use that kind of hybrid model with a memory-only backend. You would have to use at least IPC. Well, you can use it, yeah, with IPC. The only thing with IPC is that you cannot use it
38:01
through the network. Right, right. Okay, thank you. Thank you very much. We're gonna talk about how to do this. So my question for you is, obviously you've done a lot of experimenting with channels. What do you think is the most thing that's missing most from channels so far? That is missing most? Yeah, but what do you want?
38:20
That's a pretty interesting idea. But I think the things that are missing a little bit maybe is just something on top of the current interfaces that it already has, to make it a little bit more easier, for instance, to send a message to a channel from outside Django,
38:43
but to a specific user. I mean, it's pretty easy to do it with groups. But let's say that I have two servers, right? And then one server is just the front end, it just handles requests from the front end, and then the other one, it does some kind of heavy, heavy processing, like machine learning processing
39:02
or something like that. So then the first server, I would like to use Django channels to actually have these two communicate with themselves. So then on the first server, I want to send that information through the channel, and then, or through a group maybe, and then on the other server, I would like to send that just to that specific reply channel.
39:20
So just getting a hang on that reply channel, it sometimes gets a little bit convoluted. Thank you. Oh, yes, hi. I was wondering, and maybe you may have just kind of explained it, but between the persistent, the interface server and the channel layer, how do you handle persistence
39:43
if you were gonna have multiple servers? Like, at what point, 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 in the channel?
40:01
Like, do you do that in your load balancing, or? Okay, let me see if I got that question correct. And what happens here is because of the back end layer. If we use something like Redis, then it's gonna go through the network. So whenever a message comes in, then that is going to go to a channel that's gonna be called, as we saw,
40:20
web socket dot message, right? I mean, sorry, I think it was received. So when it goes through the channel, actually anybody that has access to Redis is gonna be able to read that channel. And the channels is gonna go like, okay, somebody needs 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
40:42
trying to grab that message. But one of those threads is the only one who's gonna grab that message. And then the other one's gonna go like, all right, this was already taken care of. Now when going back, that's why we have the reply channels, which are unique for clients. So whenever you put there, the only thing nobody else is going to get that message
41:00
only is that one client. Hence why Django channels, the policy of Django channels, is to deliver at most once to one listener or any kind of message, instead of deliver to many. Thank you. No problem. Just to clarify that, with the Redis, Redis handles the incoming,
41:20
but it doesn't notify in terms of outgoing, is what you're saying. Because right now, in a normal way of doing it, that's what we're doing now. Like, income to Redis, Redis would signal, right? And then once they're done processing, it would signal back to Redis and then update everybody, right? Yeah. Is that true? But now with Django channels, that's not true, or is that still true?
41:42
Wait, I got a little bit confused there. So you mean that when going back, when sending back to the client? Well, actually, yes, because the one that sends back to the client, it's also a worker thread. Because we need to remember that our reply channel, it's just that, it's another channel.
42:01
The only thing is that it has a unique string, so that way, we're not gonna have different members on that one channel. It's just gonna have one client. So whenever we need to reply something, we put that message into that channel, and then Redis is gonna go like, hey, I have something new for somebody.
42:21
The worker thread, somebody's gonna go and grab it, and with that unique channel, Django channels know how to actually route it back to the client. It's gonna go like, okay, there you go. All right, thank you. Oh, sorry. So have you played with Celery at all?
42:41
Yeah, oh, that's cool, yeah. So where I was going with that is kind of like, 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, so it's a message protocol. So the future of this, do you see yourselves
43:00
trying to push for persistent message protocol, or website message protocol in Django? Because it could grow out to include topics and fanouts, and I can see that kind of stuff happening too, so I was curious as to where you saw it go. Yeah, well, actually, the only thing is that Django channels, it kind of resembles an AMP queue,
43:22
but it's really not that. What it's trying to do is just trying to give us an abstraction layer for us to actually use something like that. So all of that is really not gonna, Django channels is not gonna try to put them together. It's not gonna try to clash them, but for instance, what I've been using it for is that I still use Celery.
43:41
So whenever a request comes in from, let's say a user pushes a button or something like that, or clicks a button, then the Celery task will start, and whenever the Celery task needs to say something to the client, it will just write something to that channel. But that's all the involvement of Django channels. Thank you.
44:01
Cool, so 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. I'm always on IRC. Special thanks to everybody, people at Django, and these guys too. Thank you. Thank you.