Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update 'Asynchronous Applications' documentation #1464

Open
ZenenTreadwell opened this issue Oct 11, 2024 · 7 comments
Open

Update 'Asynchronous Applications' documentation #1464

ZenenTreadwell opened this issue Oct 11, 2024 · 7 comments
Labels
Needs docs This feature lacks documentation

Comments

@ZenenTreadwell
Copy link

Happy to see Bottle get a version bump. I read through the patch notes and noticed added support for aiohttp and uvloop server adapters. I'm hoping to add a basic websocket implementation to my bottle server (because this project is the best), and I would like to use the right tool for the job.

According to this page of the bottle docs, the suggested solution is to use the gevent-websocket package. The library hasn't been updated in a while and I'm wondering if the solution you'd suggest has changed since the documentation was written. In this Github Issue defnull suggested using an asyncio server.

Given developments to asynchronous python libraries over the last few years, is there a more elegant solution to implementing asynchronous programming than is currently suggested by the documentation?


Also, as a higher level question - how much work would be required to adapt the current Bottle implementation to meet the newly established ASGI standard? Basically, is it within the scope of this project to fulfill that feature set or would it be a new thing entirely?

@defnull
Copy link
Member

defnull commented Oct 11, 2024

Using an highly efficient async servers (e.g. gunicorn) is easy, as long as the server still speaks WSGI to applications. WSGI is synchronous by design, though. Bottle is a WSGI framework. Supporting ASGI and async/await request handlers in Bottle would be so much work, it may be easier to just build a new framework from scratch. So, that won't happen any time soon. There are lots of nice (and very Bottle-like) ASGI frameworks out there.

Most applications do not need ASGI. Websockets are a very important exception, though. If you are fine with the synchronous nature of WSGI/Bottle and only need ASGI for websockets, then there are multiple options:

  • You could follow the very old, but technically still valid example outlined in the documentation using gevent. Not sure if I would recommend that nowadays, though. I haven't really tested that approach in years.
  • You could run the websocket part in a separate process and use ASGI or node.js or whatever is best for websockets, then put both (bottle and your websocket app) behind a reverse proxy (e.g. nginx, traefik, caddy). This is more complicated at first, but also much easier to scale horizontally if you expect lots of traffic later.
  • Or you could use FastAPI for the websocket part and mount Bottle onto FastAPI. No idea how well that works, I just learned about this possibility myself.

@defnull defnull added the Needs docs This feature lacks documentation label Oct 11, 2024
@defnull
Copy link
Member

defnull commented Oct 11, 2024

The gevent example still works, great. The last example is missing a gevent.monkey.patch_all() line though, which must happen before the first bottle import.

I just found out that the gevent-websocket library also ships with a ready-to-use gunicorn worker! When starting the bottle app via gunicorn -k "geventwebsocket.gunicorn.workers.GeventWebSocketWorker" my_wsgi:app all the gevent setup code is no longer necessary. It just works.

I'll keep this issue open until I (or some one else?) find the time to update the documentation.

@ZenenTreadwell
Copy link
Author

Great, thanks for the speedy response.

I think the FastAPI approach is a non-starter for me, the number of dependencies it would introduce adds way too much complexity to the project. I also found the greenlet/gevent stack to be rather heavyweight; I'll keep it in my back pocket but I'm pretty sure Python's websockets library is what I'm looking for.

I think the suggested approach of running an asynchronous server separately and reverse proxying to it makes the most sense to me. I'll need to find a good way of sharing application state between the two projects, or find a way to run them in a shared context.

@ZenenTreadwell
Copy link
Author

Regarding that last point, I think we might be back to my original question. Since libraries like aiohttp or gunicorn (with gevent's websocket lib) provide support for web sockets out of the box, does that mean that it would be able to serve the bottle application and also a web sockets endpoint with a shared context? Or is that still subject to the limits of synchronous wsgi?

@defnull
Copy link
Member

defnull commented Oct 11, 2024

Yes, with gunicorn+gevent you write your entire app as if you'd have an unlimited amount of threads in your thread pool and with the geventwebsocket worker or adapter you also have a magic wsgi.websocket variable in your environment dictionary if the client is actually a websocket client. You can fetch that and blocking-read from it or blocking-write to it in a while-loop for as long as you want. Without gevent this would be bad because it blocks a thread for as long as the client is connected, with gevent you have unlimited threads so blocking one is no big deal.

With aiohttp you would use something like aiohttp-wsgi to mount a synchronous WSGI app into an asynchronous aiohttp-app. The aiohttp runtime would then create a normal thread pool and run WSGI actions in that pool, while everything else runs on the event loop using async/await. Both worlds are strictly separated, although they run in the same process and on top of the same server engine.

@abersheeran
Copy link

the number of dependencies it would introduce adds way too much complexity to the project

If you want to try an asynchronous web framework with no dependencies and support for WebSockets, you might want to try baize.

@ZenenTreadwell
Copy link
Author

ZenenTreadwell commented Oct 15, 2024

So, something that I didn't really consider until I found it saved in my GitHub stars: nchan

It's a nginx library which seems to handle all of the complicated stuff in a very elegant way. You can POST data to the /pub endpoint and the data is relayed to a websocket at the /sub endpoint; it seems really well suited to my use case of sending notifications to the client. I'm already using nginx as my reverse proxy so this was a really small addition - the library is under 1MB and appears to be a very robust solution.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Needs docs This feature lacks documentation
Projects
None yet
Development

No branches or pull requests

3 participants