Python RPC and PubSub over Websockets
This is a modal window.
Das Video konnte nicht geladen werden, da entweder ein Server- oder Netzwerkfehler auftrat oder das Format nicht unterstützt wird.
Formale Metadaten
Titel |
| |
Serientitel | ||
Anzahl der Teile | 115 | |
Autor | ||
Mitwirkende | ||
Lizenz | CC-Namensnennung - keine kommerzielle Nutzung - Weitergabe unter gleichen Bedingungen 4.0 International: Sie dürfen das Werk bzw. den Inhalt zu jedem legalen und nicht-kommerziellen Zweck nutzen, verändern und in unveränderter oder veränderter Form vervielfältigen, verbreiten und öffentlich zugänglich machen, sofern Sie den Namen des Autors/Rechteinhabers in der von ihm festgelegten Weise nennen und das Werk bzw. diesen Inhalt auch in veränderter Form nur unter den Bedingungen dieser Lizenz weitergeben. | |
Identifikatoren | 10.5446/58815 (DOI) | |
Herausgeber | ||
Erscheinungsjahr | ||
Sprache |
Inhaltliche Metadaten
Fachgebiet | ||
Genre | ||
Abstract |
|
EuroPython 202128 / 115
1
3
19
25
31
34
36
38
41
42
44
46
48
52
60
61
62
65
69
73
76
82
83
84
92
94
96
103
110
113
00:00
VideokonferenzEchtzeitsystemServerClientEreignishorizontOpen SourceExogene VariableImplementierungMessage-PassingDatenverarbeitungssystemREST <Informatik>AdditionKontrollstrukturPunktwolkeAggregatzustandOffene MengeZusammenhängender GraphDienst <Informatik>GruppenoperationSoftwareKartesische KoordinatenRPCMAPZentrische StreckungInteraktives FernsehenPrinzip der gleichmäßigen BeschränktheitInstantiierungAutorisierungKomplex <Algebra>MathematikInformationBijektionGebäude <Mathematik>Umsetzung <Informatik>SynchronisierungElektronische UnterschriftElement <Gruppentheorie>DifferentePay-TVSyntaktische AnalyseVirtuelle MaschineKonfigurationsraumSystemaufrufMinkowski-MetrikDatenfeldRandomisierungMultiplikationAusnahmebehandlungMultiplikationsoperatorEinfach zusammenhängender RaumComputersicherheitKlasse <Mathematik>SoftwareentwicklerInhalt <Mathematik>CybersexGemeinsamer SpeicherUmwandlungsenthalpieFunktionalSystem FParametersystemSoftware EngineeringInterface <Schaltung>BenutzerbeteiligungDatenverwaltungMomentenproblemApp <Programm>CASE <Informatik>Ganze FunktionProjektive EbeneRouterInternetworkingFirewallRoutingRelationentheorieBitReibungswärmeBroadcastingverfahrenBildgebendes VerfahrenAbfrageHochdruckSerielle SchnittstelleRichtungSocket-SchnittstelleDualitätstheorieBeanspruchungDatenflussZeichenketteHalbleiterspeicherKlassische PhysikComputerarchitekturInformationsspeicherungRegulärer GraphMini-DiscFlächeninhaltBenutzerfreundlichkeitResultanteProgrammbibliothekPunktPhysikalisches SystemLambda-KalkülKoroutineCodeSpeicherabzugCoxeter-GruppeBestimmtheitsmaßSchlüsselverwaltungMusterspracheProdukt <Mathematik>RückkopplungInterpretiererInstallation <Informatik>Parallele SchnittstelleVerschlingungp-BlockTouchscreenKappa-KoeffizientTeilbarkeitBrowserVariableBildschirmsymbolLoopDigitaltechnikWarteschlangeFrequenzFront-End <Software>Besprechung/Interview
00:50
PunktwolkeSoftware EngineeringGebäude <Mathematik>Minkowski-MetrikAutorisierungCybersexComputersicherheitSoftwareentwicklerOpen SourceBesprechung/Interview
01:41
Keilförmige AnordnungOffene MengeWeb ServicesServerDokumentenserverServerClientMomentenproblemMultiplikationsoperatorKartesische KoordinatenZentrische StreckungGruppenoperationElement <Gruppentheorie>AutorisierungSynchronisierungDienst <Informatik>SoftwareOffene MengeAggregatzustandInstantiierungOpen SourceProjektive EbenePunktwolkeApp <Programm>DifferenteAdditionMultiplikationMinkowski-MetrikKollaboration <Informatik>DatenverwaltungArithmetische FolgeGebäude <Mathematik>Computeranimation
05:30
Konfiguration <Informatik>Reelle ZahlServerPolygonzugKeilförmige AnordnungClientRouterRechnernetzHauptidealringRichtungRPCEchtzeitsystemMessage-PassingInterface <Schaltung>Service providerExogene VariableW3C-StandardClientZentrische StreckungInstantiierungServerPhysikalisches SystemSoftwareDifferenteElement <Gruppentheorie>BeanspruchungUmsetzung <Informatik>Message-PassingKlasse <Mathematik>ComputerarchitekturCodeEchtzeitsystemInhalt <Mathematik>FunktionalUmwandlungsenthalpieSyntaktische AnalyseZusammenhängender GraphAutorisierungProgrammbibliothekSynchronisierungPunktwolkeEinfach zusammenhängender RaumFlächeninhaltp-BlockParametersystemExogene VariableSchlüsselverwaltungKartesische KoordinatenGruppenoperationEreignishorizontGemeinsamer SpeicherFundamentalsatz der AlgebraGebäude <Mathematik>BijektionInterface <Schaltung>ReibungswärmeRichtungAbfrageFirewallKonfigurationsraumRandomisierungPotenz <Mathematik>XMLComputeranimation
14:39
RPCMechanismus-Design-TheorieServerClientInterface <Schaltung>Message-PassingPay-TVFunktionalWarteschlangeKlassische PhysikSystemaufrufRPCInstantiierungMathematische LogikZusammenhängender GraphBeanspruchungInteraktives FernsehenInformationsspeicherungMini-DiscMultiplikationEreignishorizontBroadcastingverfahrenSynchronisierungMAPProgrammbibliothekBijektionCASE <Informatik>Umsetzung <Informatik>Elektronische Unterschrift
19:02
BroadcastingverfahrenKeller <Informatik>TeilbarkeitImplementierungMessage-PassingBroadcastingverfahrenClientServerPay-TVKeller <Informatik>Computeranimation
19:55
Cloud ComputingClientRechenwerkInklusion <Mathematik>Lokales MinimumMenütechnikMIDI <Musikelektronik>KommunikationsdesignGammafunktionCAMW3C-StandardZellularer AutomatMehragentensystemServerClientAbfrageEreignishorizontSystem FAdditionKlassische PhysikZeichenketteFunktionalExogene VariableFrequenzGlättungInteraktives FernsehenRandomisierungREST <Informatik>HochdruckPay-TVInformationCodeVariableEinfach zusammenhängender RaumLoopPrinzip der gleichmäßigen BeschränktheitRegulärer GraphRoutingBildgebendes VerfahrenAutorisierungProgramm/Quellcode
26:30
Graphische BenutzeroberflächeGEDCOMInklusion <Mathematik>MIDI <Musikelektronik>ServerStellenringAdditionClientEreignishorizontCodeProgramm/QuellcodeComputeranimation
27:29
BildschirmmaskeClientICC-GruppeCodeComputeranimationProgramm/Quellcode
28:04
Projektive EbeneSynchronisierungMusterspracheAutorisierungProdukt <Mathematik>Einfach zusammenhängender RaumVerschlingungComputeranimation
29:18
Offene MengeRückkopplungVorlesung/Konferenz
29:46
Zentrische StreckungMultiplikationsoperatorFront-End <Software>Einfach zusammenhängender RaumVerschlingungComputeranimationBesprechung/Interview
Transkript: Englisch(automatisch erzeugt)
00:07
Hi everyone, the next talk is from Ora Weiss and it's about Python, RPC and PubSub over
00:20
WebSockets. It's a pre-recorded talk and we will play the video and then the Q&A starts with Ora here as well and you can ask your questions to Ora about his presentation. First of all, I have to say that I'm amazed that I have to host a session from Ora and
00:47
have a great talk everyone. Hi everyone, I'm really happy you are joining me on this talk. We're going to be talking about Python, RPC and PubSub over WebSockets. I'm Ora Weiss,
01:04
I'm the founder and authorizer previously at Rookout. I come from a cyber security and development software engineering background and I love Python, probably just like all of you guys and now I'm building things with Python and I'm excited about sharing what we've built here
01:26
with you. Before we dive into the open source packages that I'm going to share with you, I'm going to go into their design and into their concepts and also how to use them. Before that, I'm going to talk about the problem space itself. As you all know, the cloud
01:45
is growing, the edge is exploding, more and more elements of software are kind of eating up the space and becoming more complex, adding more elements. It's no longer just running a simple server on one machine, it's multiple instances, it's multiple services in the cloud, third parties
02:04
interacting with one another, it's edge devices, IoT, compute devices that are deployed across the field, it's things running both on-prem and on the cloud collaborating. Obviously, crazy scale of stuff like Kubernetes and serverless where it on the fly changes the amount of instances that
02:23
you have and obviously things that are going towards the edge. With all of this complexity, our software is becoming more complex and we need to connect all of these elements together. We need to keep them in sync, we need to find a way to share data between all of them
02:41
at the state that we have on the on-prem synced with the cloud and what we have at the cloud also synced to the edge. The obvious question that remains is how do we do that? How do we connect and scale everything with this ever-growing complexity? That's what we're trying to solve with these packages. This is what we'll be talking about both with
03:04
RPC and pops up while using WebSockets. Before going into the specific packages themselves, let's look at a specific example and I brought the example that brought me to develop these packages. An open source project called Opal which you can find at opal.ac. Opal deals with
03:24
the world of authorization. Let's say we have an application and we want to control who can access it, the different roles, permissions within that app. The modern way to approach this today is to use something called OPA, Open Policy Agent,
03:42
which is essentially a microservice for authorization. The application can query it at any moment in time to understand if it's allowed or not allowed to perform an action. But as our application scales out, we are confronted with a problem. How do we keep the state of the application and the state of the authorization microservice and also the state
04:04
of all the other relevant data syncs that we have, our billing service, our sales management, all of those different elements that comprise our solution. How do we keep them in sync with our authorization layer as well as with our application? This is where Opal comes in. It's essentially a layer to synchronize the application and the
04:29
authorization layer. It uses both a server for main management and a client that sits next to each policy agent filling it with the data that it needs. It does this through a WebSocket
04:43
PubSub channel, which we'll be talking about in a minute. That channel allows Opal to keep OPA in sync throughout time as the application progresses. And with every little interaction, when you're adding a new user, when you're inviting someone new, it will integrate that
05:03
information into OPA instantly. If you're doing or you're building authorization for application, by the way, I really recommend that you look at both Opal and OPA. This is one key example of how we need to have something that is spread out our entire application with the different sidecars of authorization. We need to keep all of those
05:23
in sync with things that are running on other clouds in addition to ours. Let's break down the challenges or requirements that we have here. First of all, we need this to be real-time. We can't afford to have a polling solution. We can't have everything
05:42
delayed. When you apply an action in a modern piece of software, we expect everything to apply in real-time. For example, in the Opal case, if you're inviting a user in, you expect that user to be able to access that application immediately and now that the next deployment or when the next polling interval hits. In addition, we want it to be bi-directional.
06:05
We want both components to be able to share data with one another. The concept of a server and client when you're talking about cloud-native infrastructure kind of deteriorates. Both sides need to trigger one another sharing data and update it to one layer at the authorization
06:22
component. For example, in the Opal case, it can affect a different client or a different server. We need all of those to constantly be in sync so they need to be able to trigger one another in a bi-directional fashion. We need easy networking. We already mentioned this. We're
06:41
looking at the cloud. We're looking at the edge. We need all the different components, no matter where they are, to be able to communicate in front of the network. We'll be traversing the entire internet. We'll be traversing firewalls. We'll be traversing routers. We'll be entering VPCs and on-prem networks. We need it to be, no matter where
07:03
those software elements are deployed, that they'll be able to communicate with one another in a bi-directional, real-time way. We need something that enables us to go with easy networking, to traverse with ease. We need something, in addition, that is durable.
07:20
Because of that widespread area and a lot of different connections, a lot of those connections might be severed at one point or another. We need a system to be durable. We need it to be able to survive and reconnect as things change. Lastly, we need it to be scalable, especially if you want to run this on Kubernetes or Serverless or anything of
07:41
modern scale today. It always ends up relying on the ability to take one instance and scale it out to many to support higher workloads. These are all the requirements that we have. Now let's look at how we can use the different elements of architecture to approach them.
08:03
We'll be looking again at RPC, PubSub, and WebSockets. For the real-time bi-directional aspect, WebSockets are really a good way to start. First of all, they create a bi-directional channel. While they rely on HTTP, they enable both sides to trigger a conversation on an ongoing
08:25
channel. Unlike general HTTP or RESTful HTTP, where you trigger a request, get a response, and often terminate the session, WebSockets stay up constantly. Both sides can trigger
08:40
queries or requests on top of that channel. WebSockets also contribute to easy networking. Because they're based on HTTP, most routers, most firewalls would be very forgiving for that. Also, they save us a lot of friction with creating an easy direction.
09:00
So clients can trigger an outgoing HTTP connection going easy through the firewall, but after the connection is established, because it's bi-directional, now the server can also trigger requests on that existing connection. Durability and flexibility we're getting from RPC. The basic concept of RPC is just being able
09:23
to call remote functions. So in a minute, you'll see what we'll be doing is exposing specific Python functions to the other side. By exposing functions, we're essentially connecting the two Python interpreters, enabling any element of code to be shared between them, so we can add more
09:43
functions as we need to get to both the durability that we need to maintain that, and also to add more capabilities. Lastly, PubSub, the ability to subscribe to events and publish events and have those reach all of the subscribers, will really enable us to take this to scale.
10:05
So in a minute, we'll see we'll be taking a one-to-one RPC channel, and then we can create many of those, and on top of that, through the extensibility that we're getting out of RPC, connect it to a PubSub channel, then move from a one-to-one kind of relationship to a one-to-many
10:23
kind of relationship. So let's dive in, and we'll start by looking at the design of the first package that we've built, Fest API WebSocket RPC. It's called Fest API, by the way, because one of the fundamental building blocks that we use is the Fest API server, which I'll
10:45
elaborate more in a minute. So first of all, the basic component of our RPC connection is RPC channel. Essentially, it's a JSON-based channel that provides the ability to pass both requests and responses for functions. Our request will be targeting a specific Python method
11:08
that we exposed, and in the end, it looks something like this. As you can see in the screenshot here of the code, you can see we have a server that inherits from RPC method base,
11:22
and it exposes specific methods. For example, in this case, we can see it exposes a concat method that takes two parameters, connects them, and returns the string value. On the other side, we'll be calling these methods for an interface that looks something
11:41
like this, other.method, and calling that method. So in this case, we'll be doing other.concat and passing the two arguments that we want to concatenate. To build this, we'll be using async A, or as you can see, our functions here have the prefix async to define them as async functions using coroutines. This will really
12:05
enable our code to be suitable for real time. Things will be running concurrently within our RPC server and RPC client. Obviously, as we mentioned, we will be using WebSockets for having it bi-directional, and we'll be using Pydantic to get serialization. Pydantic
12:25
really works well with Fest API. It's a native library that Fest API uses, and we'll be using it to define our RPC messages, both for request and response. We'll be using Tenacity,
12:44
another cool library, to maintain that durability that we mentioned. Let's look at a key piece of code in our RPC server. When it receives a WebSocket connection, it reads JSON content out of it and uses Pydantic here with RPC message to parse the data.
13:07
And then we get basically a Python class called message, and we can check is it a request or is it a response, and then trigger the behavior accordingly. So that's really the basic
13:20
functionality that we have, the ability to pass on a serialized message, have it target a function with specific parameters, and have that invoked, wrapped into our response, and then sent on the wire as a response where the other side can wait on it, and then receive the response, parse it, and pass it to the calling component.
13:45
Within the RPC client, which is triggered via an async with call, we have our basic wrapping using Tenacity. Basically, call our connect method wrapped with retry, and we pass in a configuration telling it to constantly retry. So if it fails,
14:06
if it throws an exception, if it gets disconnected, Tenacity will take care of reconnecting for us. Tenacity provides flexible configuration. We can literally go into it and we want some exponential back off. We want you to wait 10 minutes before you try again,
14:24
stuff like that, and we can expose that. Fest API WebSocket RPC exposes that to the user, so you can also use it directly yourself from there, but it also comes with exponential back off of some randomization just as a good best practice.
14:40
So that was RPC. Now let's see how we take it to the next level to PubSub. So RPC enabled us to do a kind of one-to-one conversation. Now we want to go and enable the one-to-many, and we want to leverage RPC to do so. So the basic component that we've built within the
15:02
Fest API WebSocket PubSub package, which you can find here on GitHub, is the event modifier. It essentially registers subscriptions for callbacks, and you can see this is the basically the signatures of the main methods of the event modifier, and you can see the main
15:23
one that I've opened here to your callback. It literally picks up the subscription that's passed to it when you call notify, and it just calls a callback function. So that will really work well with our RPC implementation, because RPC, as you remember,
15:41
is just about calling functions. So on the subscribing side, using RPC would just be accessing the RPC channel, going into hover, and calling the subscribe method. So we're literally calling subscribe the same logic within the event notifier on the remote
16:03
component. And when we publish an event, it works the same way. We call back into the remote component and tell it, hey, publish an event for me. So just by relying on the RPC's callback architecture, we were able to plug in something really simple that just remembers who
16:25
subscribed to what, who subscribed to which topics, and then just call callbacks onto the remote side. So in that fashion, we move really quickly from having a one-on-one interaction to a one-to-many interaction. Lastly, we need to be able to not only scale out on the clients, so
16:44
imagine now we have a PubSub server, and we have many clients serving it, but we may want to also synchronize with multiple server instances, because remember, we want to be able to run this with multiple workers. We want to run this on Kubernetes with multiple instances or on Lambda
17:03
serverless with multiple instances. So now we need to sync those multiple instances. So in case we have one client connecting to server one, but server B is the one that's triggering the notification, it will propagate to the right server and then through that to the right client.
17:21
For that, we're using another library called Broadcaster, which is also really cool. It enables you to, in an abstract way, to interact and use both Redis PubSub, Postgres Listen Notify, and Kafka, all our classic message queues that we can use, and we use
17:42
them essentially as a backbone PubSub. So our own PubSub relies on the backbone PubSub to propagate messages between the different instances of the server. So this has a key advantage of shifting the workload. First of all,
18:03
deploying, let's say, a new Kafka instance can be rather heavy. By shifting the workload to the WebSocket PubSub, we basically enable most of the work to happen at each server node, and only when we have to propagate it to the backbone PubSub. So we can then utilize less
18:24
resources. Unlike our first API WebSocket PubSub that we're describing here, Kafka, even RabbitMQ, they require more resources. They require memory. They require storage on disk. They require more redundancy. So we can save a lot on those resources by only passing what we need between
18:47
servers to those theirs. But still, we can connect to them really easily with the Broadcaster interface for our FastAPI WebSocket PubSub package.
19:03
So let's have a kind of a quick review of our stack. So we're using FastAPI for the basic server infrastructure. We're using WebSockets for the client's WebSockets because FastAPI, while it's great, their client implementation has some hiccups. We're using Pydantic for
19:23
serialization, both for the subscriptions that we're passing on the wire, and obviously, as we mentioned, the messages both for RPC requests and RPC responses. And we use Tenacity, as we mentioned, for the durability factor for the ability to reconnect
19:47
when things fail. And we're using Broadcaster to expand our PubSub between servers if we need. So now when we have a basic grasp of what these two packages are and what they
20:01
deliver and how they address the problem, let's see them at work. So we'll start with the RPC side, and we can see here two simple examples of both the server
20:24
and the client using the package. Let's start with the client code. We can see that the client is running within an async IO loop and essentially just calling concatenate on the other
20:40
side. So we have client.other.concat, and we're passing the values that we want, and then we wait for it until we get a response, and we print a response out. In addition, we have the server side where we can see that we expose one method. We expose that concat method, getting those two variables and concatenating them, and
21:06
establishing that into our Fest API server via a RPC endpoint, just passed through our concat server definition, exposing those methods, and running this via UVCore. So let's just run this and see how it behaves. So we'll start with the server so it can wait
21:26
for the connection. So the server is up and waiting, and now when we trigger the client, we can see it run, and we can see that we got our concatenated string. It essentially ran on this interpreter, went to the other side, called this function, got the value,
21:46
got it back, and printed it. Never straightforward, but still a pretty cool response, and it works smoothly. Now let's move for a slightly more advanced example, bi-directional interactions. In this case, it's not only the client calling
22:06
functions on the server side, but also the server calling functions on the client side. And we'll be also using those for synchronizing between the two sides, between the two components. So you can see here that in addition to the server exposing
22:24
the concat method, now the client also exposes methods. And we have two, we have allow queries, which is essentially a function that signals an event within the client, telling it that it can start sending requests to the server. And we have allow exit, so it will tell the client to
22:44
wait a random period of time, and then exit. So the server essentially controls the interaction with the client. The client here does just as we described, it connects to the server, and then waits for the server to trigger it via calling that method and setting that event.
23:01
So it waits for that event to be triggered, and otherwise it doesn't continue. It then calls the concatenate method just as before on the server side, and prints the result, and then waits on the server to let it know when it can exit. So let's run this. Oh, one more thing. The server side, in addition to
23:27
exposing the concat method, it uses unconnect to tell the client after it waits for a while to trigger its queries. And when the query of concat, when concat is called, it also, in addition to returning the value, it also in the background triggers the allow event for exit.
23:48
Okay, so let's run these examples as well, again, starting with the server. So we're running the bi-directional server example. The server is now waiting, and we'll run
24:01
the matching client. And you can see that both sides interact, and then now after that delay, the client exited. So we saw that exact flow, and of course also the concatenated string that we wanted. So you can see we can have both server and client triggering methods at one another,
24:23
and also using those for synchronization, which is really great when we're working at scale. Let's take it a step further, and now let's talk about our pop sub client and server. Here we have a slightly more advanced example of pop sub, where we'll be combining,
24:44
in addition to pop sub, we'll also be combining a classic RESTful API server with fast API. So let's start with our server example. So our server, just as before, in its fast API and exposes instead of an RPC endpoint, a pub sub endpoint, and it exposes a regular HTTP route at slash trigger
25:12
that sends event through the pub sub. We can see the function that is called, it waits a bit, and then it publishes the events for guns and germs. It waits a bit, then it publishes an event
25:25
for germs, and then finally it publishes an event for steel and adds data. This is a reference to a book that I like, just by the way, and this is the author of that book. On the client side, we have that mirror image of a client initiating and waiting for events for both
25:46
guns and germs, having a callback to on events. So we'll be seeing this print happening when that callback happens. And we'll also have another later subscription to steal, where we're calling a different method, where we'll be printing this information point,
26:04
and also terminating the client, which is kind of similar to our allow exit kind of behavior before. And obviously running this as async AO. So, okay, let's run this again. We start with the server, just having it up and running. We'll have the client running and nothing will happen
26:24
here initially because everything is waiting on our trigger event. So now let's go and approach our server locally. And so we triggered the server and we see that in addition to the
26:48
trigger went correctly, and it triggered the events on the client side, as well as the final event triggered by this goal also passing data. Awesome. And now if we had, we can have multiple
27:04
clients subscribing here, you know, we can actually do that. You know why it's not that interesting. So we can have multiple clients subscribing here, and all of them receiving the
27:23
updates at once, running in parallel. So we review the code. So now you know, if you want to use these packages, you can go in fetch them from GitHub and or from PIP, you can just PIP install
27:47
them. PIP install, you can do PIP install, Fest API, WebSockets, RPC and PIP install, Fest API, WebSocket, PubSub, and they're ready to go. And you have those code examples also available in documentation on our GitHub. Really easy to start. So that was our session.
28:08
I hope you enjoyed it. I invite you to stay a while and listen a bit further and ask me questions in our breakout room, which you'll be getting a link to in the chat right now. And of course,
28:21
you're welcome to look at these packages that I've shared with you, as well as other projects that I've built that use this. Authorizing that I've built with Fassaf Cohen, which also leverages Opal AC, which is a solution to manage your authorization. And Opal AC that I
28:42
mentioned, that synchronization layer that uses Fest API, WebSocket, PubSub to make sure that the data reaches into your open policy agent. And also Rookout, which is a previous company that I created, that while not using these packages, uses a similar pattern to enable
29:04
you to set breakpoints on the fly in production. So those breakpoints, when they're triggered through a WebSocket connection that runs within your code, waiting for you to set that breakpoint. Cool. Thank you very much. I hope you enjoyed this talk and look forward
29:22
to hearing your questions and getting the feedback. And both here on PyCon, as well as on GitHub, you're welcome to open pull requests, issues requests, and I'll be happy to chat with you. Thank you very much and enjoy the rest of the convention.
29:49
Hi all. How are you? Great. Hope everyone enjoyed the talk. Unfortunately, the talk was a little bit longer, but I have, I think we can cut one question,
30:05
which is why would you use PubSub over a WebSocket on message? Over on message? So why would you use PubSub in general? So the PubSub channel will give
30:21
you the kind of scale to, instead of having one, you can have many instances at once. And with the PubSub solution here explicitly, you can also scale it out. As I mentioned, they talk through other PubSub solutions, so you can also scale it out on the backend side. Hope that covers the question. Okay. Unfortunately,
30:47
I have some connectivity issues, if that's okay. I don't think that we have more time for another question, but you can always reach all that room. If you want to check me for a longer time, you can find me at opalac. There's a link to
31:06
Slack channel there. Happy to answer questions all day long. And I have to say that this was a great talk for me. Hope, glad you liked it and hope everyone enjoyed. Bye. Thank you. Thank you.