Async Web Apps with Sanic
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 | 160 | |
Autor | ||
Lizenz | CC-Namensnennung - keine kommerzielle Nutzung - Weitergabe unter gleichen Bedingungen 3.0 Unported: 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/33701 (DOI) | |
Herausgeber | ||
Erscheinungsjahr | ||
Sprache |
Inhaltliche Metadaten
Fachgebiet | ||
Genre | ||
Abstract |
|
EuroPython 2017121 / 160
10
14
17
19
21
32
37
39
40
41
43
46
54
57
70
73
85
89
92
95
98
99
102
103
108
113
114
115
119
121
122
130
135
136
141
142
143
146
149
153
157
158
00:00
App <Programm>SoftwareIntelCDMAGebäude <Mathematik>Quick-SortKonfiguration <Informatik>TermInversePunktSoftwarewartungMultiplikationsoperatorSelbst organisierendes SystemAutomatische HandlungsplanungSprachsyntheseSoftwareentwicklerLeistung <Physik>MAPÄhnlichkeitsgeometrieZahlenbereichProzess <Informatik>MultiplikationOffene MengeLie-GruppeMomentenproblemEreignishorizontTropfenImplementierungKartesische KoordinatenBildschirmfensterProjektive EbeneCodeClique <Graphentheorie>FehlermeldungAdditionBeweistheorieResultanteBitComputerspielGruppenoperationExogene VariableBenutzerbeteiligungKoroutineFramework <Informatik>PlastikkarteArithmetisches MittelSpeicherabzugDruckspannungStatistikMereologieTopologieUmwandlungsenthalpieKlasse <Mathematik>DatenbankInternetworkingTaskÜberschallströmungGebäude <Mathematik>Vorzeichen <Mathematik>WellenpaketLoopReelle ZahlÄquivalenzklasseApp <Programm>StandardabweichungWeb-DesignerOpen SourceWeb-Applikation
08:43
Exogene VariableWinkelE-MailSpeicherabzugSchwerpunktsystemSoftwareentwicklerMultiplikationsoperatorLoopFunktionalKontextbezogenes SystemQuick-SortOffene MengeEinfach zusammenhängender RaumEreignishorizontDemo <Programm>App <Programm>TelekommunikationServerTemplateSoftwareHochdruckWeb-SeiteSocketSpeicherabzugKonfiguration <Informatik>Befehl <Informatik>ClientInformationGeradeDickeVersionsverwaltungDifferenteSchlüsselverwaltungFunktion <Mathematik>KoroutineSocket-SchnittstelleFahne <Mathematik>SchnittmengeBenutzerbeteiligungATMVariableASCIIRechenschieberData DictionaryZahlenbereichBrowserZellularer AutomatRegulärer GraphBitMomentenproblemMailing-ListeCodeWurzel <Mathematik>Framework <Informatik>Gewicht <Ausgleichsrechnung>EchtzeitsystemCluster <Rechnernetz>Familie <Mathematik>TeilmengeDemoszene <Programmierung>Codierung <Programmierung>RoutingURLAnwendungsspezifischer ProzessorZweiPunktRauschenOffice-PaketMusterspracheDialektTopologieLastGanze Funktionsinc-FunktionGebäude <Mathematik>ProgrammbibliothekMathematische LogikGüte der AnpassungSchreiben <Datenverarbeitung>Selbst organisierendes SystemErweiterte Realität <Informatik>Fehlermeldung
17:16
ZeitbereichInnerer PunktMessage-PassingProtokoll <Datenverarbeitungssystem>Inhalt <Mathematik>SurjektivitätEntscheidungsmodellSoftwaretestStatistikPhysikalisches SystemIntegralWorkstation <Musikinstrument>SoftwaretestRichtungVirtuelle MaschineEinfach zusammenhängender RaumDatenbankInverser LimesBitrateFunktionalDreieckKlasse <Mathematik>KonditionszahlProgrammbibliothekEreignishorizontPunktGeschlecht <Mathematik>MultiplikationAggregatzustandVerschlingungProzess <Informatik>DokumentenserverLoopCodeGeradeMinkowski-MetrikEinsSoftwareentwicklerRechenschieberWeb SiteMAPKomplex <Algebra>Rechter WinkelVersionsverwaltungMereologieInformationMultiplikationsoperatorWort <Informatik>Textur-MappingComputerarchitekturVorzeichen <Mathematik>ServerUniformer RaumClientTeilbarkeitAusnahmebehandlungArithmetisches MittelVollständigkeitPhysikalischer EffektFramework <Informatik>App <Programm>Zusammenhängender GraphTypentheorieSocket-SchnittstelleCookie <Internet>ZahlenbereichKonfiguration <Informatik>Leistung <Physik>ATMWeb-SeiteRuhmasseBildschirmmaskeAbgeschlossene MengeOffene MengeSichtenkonzeptQuick-SortWeb-ApplikationEin-AusgabeRoutingService providerBenutzerbeteiligungOverhead <Kommunikationstechnik>p-BlockHochdruckSchnittmengeBefehlsprozessorProgrammschleifeMaßerweiterungGüte der AnpassungSocketBildschirmsymbolWeb log
25:50
Konfiguration <Informatik>UntergruppeComputersicherheitMultiplikationsoperatorSchlussregelKonfiguration <Informatik>PartikelsystemQuick-SortGeradeEnergiedichteDigitales ZertifikatPhysikalisches SystemInterface <Schaltung>StandardabweichungUniformer RaumInstantiierungServerTopologieFramework <Informatik>BenutzerbeteiligungProgrammierumgebungAuthentifikationGewicht <Ausgleichsrechnung>ProgrammbibliothekPerspektiveLoginProjektive EbeneBitDienst <Informatik>PunktspektrumVersionsverwaltungGerichteter GraphFehlermeldungAutorisierungMaßerweiterungPaarvergleichSpeicherabzugMomentenproblemMereologieEinfach zusammenhängender RaumIntegralAutomatische HandlungsplanungPunktOrakel <Informatik>DifferenteApp <Programm>SynchronisierungFront-End <Software>EindeutigkeitProtokoll <Datenverarbeitungssystem>Kartesische KoordinatenElektronische PublikationÜberschallströmungWeb-ApplikationCASE <Informatik>GatewayFlächeninhaltLoop
Transkript: Englisch(automatisch erzeugt)
00:04
Hi, thanks everyone for coming along today. The first thing that I want to talk about quickly is the error I made in the title of my talk. Specifically, it's to do with the word apps. I mean, what is a web app? So if you just ignore that and just think of it
00:22
as more as building web things with Sanik. Which I know is not much more helpful, but you'll maybe understand more as I go into the talk, but I think it wasn't the best title. So what I really want to do today is talk to you about my journey learning Sanik
00:40
and learning the Async IO ecosystem in terms of doing web development and web frameworks. But first of all, just quickly, who am I? I'm a Scottish Pythonista. And speaking of which, it's extremely hot here. And my hotel AC's not working, so if I fall asleep,
01:00
it's because I didn't sleep well last night. Otherwise, I'm the Python Glasgow organizer. I'm an open source maintainer of a number of projects. Probably the most popular is MKDocs, but I've actually been fairly inactive on that lately. I'm an OpenStack developer at Red Hat as my job. And in the past sort of 10 years almost,
01:21
I've done a lot of Django and Flask development. So I've done quite a lot of web development. So this has been really quite an interesting lesson for me in terms of learning about Async web frameworks. Because while the actual web development can be very similar, there's quite a specific mindset that you need to take
01:42
because otherwise there are pitfalls that you'll hit. But first of all, I just want to talk a bit about how we got to this. Okay, just checking, I was updating. How did we get to this point of where people are able to use Async IO for this kind of development?
02:02
And I think a lot of it comes from the transition that's happening from Python 2 to 3. I feel like as a community, we are kind of at the tipping point where most people should either be on Python 3 by now or they should have a clear transition to Python 3 that's underway. And if not, you're gonna be in a nasty place in not too long, I think. But if you can make the assumption
02:21
that most people are on Python 3, then most of them are also on Python 3.3 or above, which means they have the ability to use Async IO. So this talk is not really about what Async IO is, but I just want to quickly define it for people if I can, which is a fairly tricky thing to do
02:40
because it's something which could have multiple talks itself. It's quite a big subject. But essentially, Async IO provides people a way to have single-threaded concurrent code using coroutines, and essentially you have an event loop. So this is something which isn't particularly new.
03:01
It's not an innovation in Async IO. It's twisted, it's been doing it for a long time. Tornado done it more recently. Node.js made it very popular in the JavaScript world. However, I think the real important thing about Async IO is it's given everyone a common base to work on.
03:21
You don't end up with silos where there's all these twisted projects. Hopefully, everyone will start moving towards Async IO as the standard event loop, which they can then build an ecosystem around and improve things. So I think that's a really important, and I think that's the most important thing that Async IO has actually done. I have a confession to make, but initially when I tried Async IO,
03:41
and that was about two to three years ago, I essentially dismissed it. I didn't like it. It felt awkward. For those that remember, and I guess it was before Python 3.5, you had to use a decorator to specify coroutines. You had to use yield from. And it just felt kind of awkward to me. It didn't feel like regular Python.
04:01
But with the addition of the Async and await keywords, I feel like it's a lot more natural and a lot more comfortable to use. I have some examples of these, so if you're not too familiar with them, you'll see them in a bit. But the point of that is that I've had a lot better experience using Async IO this time around. So if you have looked at it in the past and you've maybe dismissed it for similar reasons, it might be time to start taking a second look.
04:24
And that then takes us to Sanic, which is the thing which binds this whole talk together. Sanic is a small, contained, bare bones web framework. It's got a similar scope to Flask. I don't know if they have any plans to change that over time. I suspect probably not.
04:40
And it's gonna, so Flask is really powerful for being minimal, but then it's really powerful because of the ecosystem that's built around it. And I think that Sanic over time will have an ecosystem which hopefully builds and adds this other similar levels of power. And if anyone's sort of wondering what is special about Sanic and using Async IO,
05:02
why is it worth the effort compared to Flask? What can you do that you can't do otherwise? So I find this quite hard to explain. And this is because I'm probably not an Async IO expert, but essentially the event loop allows you to sustain or keep multiple connections open at the same time.
05:20
So that means you can take multiple requests and process them, and you'll just be waiting for IO. So say for example you have a web app which has an endpoint which requests something from a database. When your code reaches a point where it makes a request to the database, it can release, that IO will happen in the background essentially, and then another request can be processed at the time.
05:42
And you'll keep like switching between the different tasks on the event loop. So say for example, the equivalent in say something like Flask would be that every request would be processed one by one. It would wait for the request to start, to finish, and then they'd be completely sequential.
06:01
Whereas with Async IO, they're concurrent essentially. And for people that don't understand the Sanic reference, the web framework is named after this internet meme, which is maybe a sign of how serious it is, but that fits in quite well with the Python ecosystem I think.
06:20
And I don't fully understand the meme, I have to say, but essentially I think it was a kid or somebody had done a really bad drawing of Sonic, the hedgehog, and people just found it hilarious and shared it, and you know, these things explode. But I mentioned that there's a kind of explosion around Async IO recently in terms of frameworks and options
06:43
so what made me pick Sanic over the others, there are a whole bunch of other competing web frameworks which are hoping to get users. And the number of reasons, and honestly they're fairly simple, it just seemed like the easiest to use and the quickest to get started with. As someone that's done Flask before, it seems very familiar.
07:02
And it just didn't really get in my way, it essentially provides you with a way of doing your request and your responses, and then you can call out to other parts of code as you need, which is exactly how it feels when you're working with Flask as well, I think. So I started using it initially probably in early January, I think,
07:22
and I think I was quite lucky as well, to be honest. It seemed like the most active and it seemed like the nicest to use, but then looking back at the stats now, it's really the only one that's gained traction and it's the only one that's really active on GitHub with lots of issues and pull requests and community discussion. So I think I jumped on the correct train there,
07:41
which was definitely partially luck, but also probably a testament to how easy it was to use. And getting started is as easy as you would expect. There is one catch, and I found out that Sanic doesn't actually work on Windows at the moment. The reason for this is that rather than using
08:02
native asyncio, it actually uses uvloop. This is a faster implementation of asyncio written in Cython and largely on, say, on Macs and Linux, that's just an implementation detail you can ignore. They're compatible in drop-in replacements, but if you try and install Sanic on Windows, you actually get an error at the moment.
08:20
I thought it would fall back to asyncio, but I found out earlier, somebody showed me on Windows, that it'll actually just, the installation will fail and complain that uvloop does not support Windows. So I'm not sure if that was an aggression or what happened, but hopefully there'll be a way to use it on Windows at some point. So this is the sort of the mandatory hello world,
08:44
which shows you the sort of the very bare bones API. And again, I'm gonna reference Flask quite a lot, but it will seem very familiar to Flask developers. Unfortunately, with the layout of this room, it's quite hard for me to point up there. Even with my laser pointer, it's kind of above me.
09:02
But you can see the, so Sanic has the concept of apps. And that's probably why I include apps in the name of my talk title. But essentially, you define an app to represent the, what you're building, and then you add roots to it just like you would in Flask.
09:20
The key difference here is the async keyword. So if you're not familiar with asyncio, this is the syntax that was added in Python 3.5, or I think, although I did not write down the version here. And what that does is it tells Python that this is a coroutine, this function. So that means that you can await on it,
09:41
and it can await on other coroutines internally inside it. But otherwise, this is just a very simple example. It just returns the plain text, hello world. And it's a fully working example, so as long as you've got Sanic installed, you can just run that. And when you do, this is the output that you get.
10:03
So this is the, obviously, the ASCII version of the drawing that we've seen earlier. And this is one of the things I think Sanic is doing really well. We could do with some more innovation in ASCII art and entertainment when you're running your apps. Jerking aside, it's actually reasonably useful
10:21
because that will only appear when you're running the app in debug mode. So it's a good red flag that you've forgotten to turn debug off. Otherwise, there is the standard things you would expect. This is just a quick example showing you how you'd return text,
10:40
plain text like we did in the first example, returning JSON and running HTML, which could obviously be like a rendered Jinja template or something like that. But what I don't really want to do is basically talk you through the documentation, talk you through the API. So we're gonna try and just do a slightly more interesting example, and hopefully I can talk you through that.
11:03
So I think WebSockets are one of the best ways to demonstrate why an async IO framework can be useful. For those of you that don't know, WebSockets are a way for your JavaScript to speak to your server in essentially real-time communication.
11:20
So rather than polling for updates, for example, they'll open a connection when the page loads, and then they'll just sit there waiting. Well, actually, they can send data to the server as well, but they'll also receive data from the server. It's a two-way communication, and it's essentially instantaneous, I mean, other than the sort of network latency. But it allows you to do real-time websites,
11:43
which is really good for things like chat or notifications and so on. Anyway, for the WebSocket support in Sanic, you need this extra package. So this is an optional dependency, essentially. It's an async IO WebSocket library, which is really nice. So even if you want to do something
12:02
with async IO and WebSockets, but not with Sanic necessarily, I think this is the best option. It's written by, I think it's one of the Django core developers originally, but not used in Django itself as far as I'm aware. So when you have installed that, you can then use the app.WebSocket function,
12:23
or decorator, sorry, to define a WebSocket endpoint. So again, this is a very simple example. We have the async keyword to tell us a coroutine, and then we have the two awaits. I can't actually point, I can't read that,
12:40
so I'm just gonna have to explain it. Yeah, so if you're new to this stuff, this can seem like quite a strange pattern, because it looks to you like this function could just lock up indefinitely, because it's a while true, it's an infinite loop. But actually, every time you get to the awaits, so when you have the await WebSocket.send,
13:00
and the await WebSocket.receive, it will actually, the IO for that will happen in the background. It'll be waiting there for something to be sent, or something to be received, and then it'll return to the event loop, and then other requests can be processed concurrently. So this is why it's so important to have something like async IO for this, where you can have concurrent requests.
13:22
You can't really do WebSockets and something like Flask, because it requires you maintain the connection, and keeping many connections open in Flask just doesn't really work. And the same applies to Django and things. There are ways to do it in Django now,
13:41
and what people used to do is they would run something like Tornado or Twisted, and they'd have a WebSocket server, and then they'd have the Django or Flask server, and then they'd speak to each other behind the scenes, and they'd sort of send notifications, but you have to deal with keeping them all in sync and everything. Anyway, this is a very simple example from the documentation, and I think we can do something a bit better.
14:00
So, in danger of angering the demo gods, if you could all just try and go to this web address, it'll be kind of interesting to see if this works at all. You won't use much data, so you can use your regular cellular data, and thankfully, if you're a European, you won't have any roaming charges now.
14:21
But essentially, what this does is it shows the number of people that are connected to it, and it shows a list of the user agents that people connected. I'm trying to load it now. So, it might take a moment for the Heroku app to start up. Has anyone managed to load it?
14:40
How many people are connected? Does it tell you? Okay. All right. I was worried this might happen, but essentially, it's a bit of fun showing you. I can still walk you through the code in the same way.
15:01
20 plus, that's pretty good. So, I've done a demo of this talk in Glasgow, and I had far less people at it. And I have no idea how many it can handle before it falls over, but it seems to be better than the Wi-Fi, but that's not too surprising. How many? 31, that's pretty good.
15:23
Yeah, so, all of you are basically, all your requests are concurrently open and all being handled, and they're sitting in the background waiting for the IO events to finish. And the nice thing about it is how little code is actually required to make this demo.
15:42
So, this is a slide where I really needed to be able to point, but I'll just talk to it from top to bottom. So, the first two variables at the top, the connected equals set and the user agents, they're essentially tracking the web sockets that are connected. So, the number of web sockets is connected to the set. The user agents is then just a dictionary of user agents,
16:02
which I routinely send to the browser. And we have our coroutine again, which is called feed. And when the request is opened, the web socket is added to the connected set. And then we just take the user agent from the request and add that to the user agents dictionary.
16:21
And I have a little printing statement which was useful from the console, and I probably should have removed that. Funnily enough, I said that the last time I gave this talk, and I never removed it. But then we go into the actual loop which is happening here, which is then sending the data back to the client. So, what you can see is I've got a web socket.send,
16:40
and it's just sending JSON, it's sending the user agents, which is a dict, as I said, and then the web sockets, I'm just doing the length of that, so it's just sending the number, so it's more efficient. And then we await on that data to be sent, and it just happens over and over. And what we have, the next line is the asyncio.sleep. So it's sleeping 0.1 seconds, so that means it's sending the information updates
17:02
to the client every 0.1 seconds, assuming everything goes okay. The one thing that's really important to hear, and this is an example of where you need to understand asyncio and make sure you don't do anything which is blocking. You can't use, or you could, but it'd be a bad idea,
17:20
you shouldn't use the time.sleep function here, you have to use the asyncio.sleep, because when you use the time.sleep, it would just block that loop at that point, but when you use asyncio.sleep, it then releases back to the event loop and allows other requests to be processed. So, the thing with something like asyncio, it's not that you can't do blocking code,
17:40
it's just that you need to make sure your code is written in a way that isn't blocking. And this is one of the gotchas I find, it's because you might be trying to use a third-party library, but if that library does anything blocking, then that will affect your run as well. And then, in the finally part of the try-finally, we just do some cleanup. So, we remove the connected web socket,
18:01
and then we remove the user agent and print out just the number of connected sockets for my debugging again. So, if anyone still has it open, you'll see that that number will decrease as people start to close it as well. So, it's quite nice, you get the real, the real-time updates there. So, for example, this could be a very simple tool
18:21
to just show people how many other people are looking at a webpage, which perhaps could create FOMO because it's like 20 people are looking at this hotel. Book it now. I think there's one website icon that does that. Oh, and the one thing I should note about the web socket, so when somebody closes the tab,
18:42
the next time that we try and send data to that web socket, you'll actually get an exception, which is something like web socket closed. So, that's when you break out of that loop, and that's when the finally is called. So, we never close the web socket on the server side. That's only ever done on the client side. And then Sanic just handles that exception
19:02
as a like end of request type thing. It doesn't treat it as an error. It's just like we're done, we're good. And then just for completeness, this is the JavaScript I wrote, and it's kind of horrible. It turns out it's actually quite hard to do something very concisely in JavaScript when you want to deal with the web sockets.
19:21
I'm not really gonna talk through this. I mostly added, so if anyone stumbles across the slides, they've got a mostly complete example they can work with. I actually have all the code in a GitHub repository, so if anyone's interested, I can link you to it. I forgot to add that link to my slides, but it's pretty easy to find as well.
19:41
But what I found really exciting and really fun about writing this is the full thing is only 85 lines of code, so that's the Python, the HTML, the JavaScript, the Heroku config, which is only a couple of lines, admittedly. But creating something like this, it was fun, but also you can see the path of how this could be useful,
20:01
even though it's such a short example to write. Of course, with something like web sockets, the complexity comes at the next stage. It's what you do with this. So say, for example, if every web socket was making a request from the database, you could potentially be in danger of overloading your database with connections. So in the app that I'm using Sanic for,
20:24
in my non-toy app, not this one, it uses the Heroku Postgres, and I'm on one of the cheaper tiers, so you only get 20 connections or something. So it's very easy to have too many web sockets open that you run out of connections. But you can get around these problems using things like pgBouncer, Postgres Bouncer,
20:40
and have that running on each of your Heroku dynos, which then means you have potentially 100 connections or so, which only translate into one or two real connections. But I mean, that's just an example. But yeah, so this is a very simple one, but you will find that the complexity does come later.
21:01
And I did say I'm not gonna read through the documentation of Sanic, but I just wanted to highlight a couple of the, sort of the common features that people have asked me. It's like, does Sanic have this? Does it not have this? So just to quickly mention them, class-based views are there. So these are very like Flask's class-based views. So this means that rather than having a standard function to handle your request, you can have a class
21:21
which breaks out your post-gets and the other types of requests, which is quite a nice way of doing it. There are blueprints, and these are, again, very much like Flask's blueprints. You can see, they actually say in the Sanic documentation that they are Flask-like, I think. So they really are trying to mimic the Flask API
21:42
where it makes sense. So the blueprints are a way for you to write reusable apps which can then be added on to endpoints. So it's kind of hard to explain, but basically it's for making reusable web apps or components to go in part of web apps. There's also an unopinionated configuration which provides multiple ways of loading up the config
22:01
that essentially acts like a dictionary, so it's easy to store the config how you want. And then it's got support for things like cookies and so on and everything you'd expect. So when it comes to testing, you need another optional dependency. So this is AIO HTTP, which, as far as I'm aware,
22:20
is the most common HTTP requesting async IO library. So essentially it's the requests of async IO, although I did hear the request is gonna have a async-compatible part to it added at some point, but I don't know when. But anyway, for now this is, I think, the most popular.
22:41
And Sanic uses it internally to make requests to itself, which allows you to then test your app with it, is my understanding. And this is a very simple example of how you use it. And really, testing with Sanic is simple, because your Sanic layer is such a narrow layer in your app, but the challenges I found with testing
23:02
were actually much harder in general when using an async IO app, just because, so when you have all your code expects to be run on an event loop, so that means that essentially your tests have to set up an event loop, run it once, and then tear it down again, which is quite an overhead for each of your tests, and if any of your tests misbehave,
23:20
so for example they don't shut down the event loop properly for some reason, then you'll have a test which just gets blocking because it's waiting, it's got like an event loop that's stuck open. And yeah, so something I would actually be really interested in, and this is kind of a request out to anyone else that knows about this, is some input on how to best test async IO or asynchronous apps, just in general,
23:44
somebody should submit a talk on that, or a blog post or something. That's my request. But it's definitely not a fault on Sanic itself, I think it's just the more inherent complexity of your overall sort of architecture as it changes.
24:00
This is just a small note, so this is something that I missed when I first was using Sanic, and it greatly impacts the performance. So the thing you should be looking at on this slide is the workers equals eight. So if you don't provide this, Sanic will just default to one worker. And what it means is it will spawn up multiple processes,
24:22
which will then route your requests across these processes and handle them. So it obviously makes your app run a lot faster. So this is quite similar to something like G Unicorn, which will spin up say multiple Django or Flask processes and route the requests. But then with Sanic you have essentially
24:40
an event loop in each request, sorry, in each process, so you've got multiple event loops going on, and you should be able to get quite a lot of throughput doing that. The documentation or the Sanic developers, at least they seem to recommend one worker per CPU that you want to dedicate to Sanic. So if you have a four-core machine,
25:01
you might want to give it all four cores and use four workers, or you might have something else running on there, so maybe you only give it two. The ecosystem is probably the biggest sacrifice that you'll make if you were to head in this direction compared with using a more established framework.
25:21
So there is a small but reasonable set of extensions listed in the Sanic documentation. That seems to be the best sort of collection of them. But it does feel like your mileage will vary a lot with all of them. And more often than not you end up having to roll your own integrations.
25:40
So there was, I don't know, I've tried a few. There was a Sanic limiter, which is a rate limiter. That seemed to work pretty well, but then I tried another one to do with session handling, and actually that didn't work well for me because it didn't provide the backend I needed, so I ended up writing my own session handling, which is kind of a pain.
26:01
And really I should probably rip that out and release that as a Sanic Postgres sessions or something, but I've not done that yet. If anyone's interested I could look into doing that. And then there's, you then have to start looking at how you would integrate with other systems.
26:20
So I've mentioned Postgres a few times, so it's not a surprise to people that I will be using that. And the thing with Postgres is you need to make sure you're using a non-blocking Postgres library. So the most common one is AIO-PG. And it nicely provides integration with SQLAlchemy, so that allows you to use SQLAlchemy with a non-blocking connection,
26:42
but it only allows you to use certain parts of SQLAlchemy. So you can only use the core API, you cannot use the ORM API. So people who are familiar with SQLAlchemy will probably, people tend to use one or the other, you don't tend to use both. I used the ORM API until I started doing this,
27:00
and then I had to use the core API. And they're both fine, but it's just, I don't know, it's just a pain that you have to be aware of what you can and can't use, otherwise you'll run into trouble. So I think it's kind of interesting to think about when should you consider using Sanic. So my talk title is to do with web apps,
27:22
but I don't think people should really be looking at building a large web app with Sanic. You want to think of it more about high-throughput services, something that you need to go really fast. Or something like a microservice would work really well, so it's something that's quite lightweight that's gonna get lots of requests. Or smaller web apps do work.
27:40
And it's not to say that you couldn't do a larger web app, I think it's just when you start to require things like sessions, and then you start to have to roll your own, and then you'll need auth, but I'm not sure there's many authentication packages out there, it just becomes a lot of work. So maybe as the ecosystem grows, then maybe it'll become more like Flask, where you can just add these extensions, and it becomes almost like a full-stack framework. But at the moment, I think it works quite well
28:02
as sort of discrete, small services. And I just quickly want to note the other options that are available. And this is something which is a bit of a tongue-swister to explain, but I think a project that we should be keeping an eye on is UVcorn. So this is by Tom Christie,
28:22
he's the author of the Django REST framework, so he's very well-experienced in this kind of area. And UVcorn is a commando of GUnicorn and UVloop. So he's essentially writing an AsyncIO version of GUnicorn,
28:42
but using the UVloop rather than the standard AsyncIO loop. And this will then use the ASGI interface rather than the WSGI interface, which is the standard web server gateway interface used by Flask and Django and everyone else. The reason that this is so important is all of, so Sanic, for example,
29:00
it kind of has to mangle AsyncIO on top of WSGI, which is never designed for Async. So yeah, I would definitely check out UVcorn, but I know it's not ready yet. Tom actually tweeted a couple of days ago, I've seen that he thinks it's not ready for prime time. But I think it's definitely gonna be
29:21
a promising option for the future. And with that, I think I'm actually ready for questions, which is good, because I'm almost out of time. So I'm not sure we have time for questions. Thank you, we don't have time for questions, but this is actually the last talk in this hall, so please.
29:49
Did you try and manage to success configuring WebSocket Secure? Yes, so the example I had was actually using WebSocket Secure. So Heroku magically made the app run HTTPS for me,
30:03
and it's using, so you can see, in the top line there, it says it figures out whether it should use WSS or WS as the protocol for the WebSocket connection. Okay, we have problems with that on Sonic, so that's all I'm asking.
30:20
But yeah, it seems to just work, which is great. I had very little to do with it. Can you show the configuration file somewhere? Pardon? Do you have configuration files for Sonic, or for, so where you provide the certificates? So because I ran it on Heroku, it's all handled for me. Okay, so there's a different case.
30:42
Other questions? So maybe you've picked Sonic over, for example, AIO HTTP for speed, right? No, not necessarily for speed.
31:01
I actually tried AIO HTTP, which is one of the, I guess, other more popular frameworks, and so I only experimented with it for a short time, and I think it was probably more just the API. I'm not sure how similar it is. I did, I'm afraid I can't remember the comparison well enough now to comment, really,
31:21
but I just found it didn't enjoy it as much, perhaps it's the best way. Or it wasn't as easy to get started, perhaps. Okay, so do a quick follow-up, maybe comment or call for comments. So do you feel that we are getting too many frameworks? Or maybe we should focus, for example, on creating libraries, so every other framework
31:42
doesn't have to repeat mistakes of every other framework, for example, in the company? I guess, I mean, are we creating too many? I don't know, the answer's kind of a yes and no. I do think this is why Tom's project, UVicorn, is important, because it's implementing the base layer in, I think, a more correct way,
32:01
and then maybe over time, something like Sonic could move to that, and then hopefully they could then remove a bunch of the nastiness they've had to do, and maybe AIO HTTP could do the same. So, yeah, it's hard to say, because I think also there's a lot of innovation going on at the moment, so it's important for people to experiment in different ways, but I think over time,
32:21
we will start to converge together, hopefully. Thanks. How do you deal with login in a synchronous environment?
32:47
That's a good question. I'm not sure if there's any particular, I've not done anything particularly special with it, to be honest. I maybe need to check my logging's not working.
33:02
Check my logging's working okay. I'll actually try to answer here. Maybe you can actually try to keep a unique request ID for each request, and then include it in all the logs, so they can actually combine, and see all these are all connected and isolated from the other one.
33:21
Anyone else? I can answer the one regarding logging.
33:41
So, Sonic has implemented logging, so we can just import logging library and do logging.emit, and that's the new Python 3.way. It's very hard to overwrite the default logger. I tried, and failed. But you can also pass the configuration for the logger, like from the dict,
34:03
that's also used by other Python applications. Configure from the dict. The same type, basically, of Python. Okay.
34:21
Thanks a lot, Google. Great talk.