etianen / aiohttp-wsgi

WSGI adapter for aiohttp.
https://aiohttp-wsgi.readthedocs.io
BSD 3-Clause "New" or "Revised" License
232 stars 20 forks source link

Change the request handling to be async #25

Closed DaRoee closed 4 years ago

DaRoee commented 4 years ago
etianen commented 4 years ago

Thanks for the MR!

However, I think it's important to point out here that buffering the request/response is actually a feature here!

Because the WSGI requests are handled in a thread pool which typically only has a few threads, it's important that WSGI handlers run as quickly as possibly to avoid deadlocking the server. A slow HTTP client (e.g. a mobile phone over GPRS) can take many minutes to send / receive a HTTP request, resulting in a worker thread being tied up for the entire time! Even worse, an attacker can craft a malicious request that deliberately does this:

https://en.wikipedia.org/wiki/Slowloris_(computer_security)

This is why reverse proxy servers like NGINX deliberately buffer the entire request/response before handing it off to the backend worker processes. It's also the strategy taken by pure-python WSGI servers like waitress. Servers which don't buffer the request/response, like gunicorn, strongly advise being deploying behind a buffering reverse proxy in their docs.

https://docs.gunicorn.org/en/stable/deploy.html

Even worse, last time I benchmarked, allowing the WSGI workers access to the streaming request/response gave substantially worse performance than buffering, due to all the coordination required between the asyncio and threaded parts of the code. Coordination between different threads can be pretty expensive, so is often best left to a minimum surface.

However, the whole point of this module is to allow sync WSGI code to exist alongside async aiohttp code. So the few routes that need async behaviour can be written using the aiohttp handlers, and the rest handled more straightforwardly in sync code.