Debusine's Django middlewares should be asynchronous
When profiling Debusine, one can see that we're spending noticeable amount of non-idle time in Condition.wait. It's so many that the profiler observes the function while it is working. A significant fraction of them happen in asgi.AsyncToSync or asgi.SyncToAsync. What we have is an asynchronous server running synchronous middlewares wrapping an asynchronous application. The transition through synchronous middlewares is transparent, but it incurs moving them to separate executor threads. By default, Django middlewares are synchronous only. We should try making them asynchronous. I expect two benefits:
- We save the inter-thread communication and moving the request between threads. The request latency is expected to reduce slightly by a relatively fixed amount. As such, this should slightly improve throughput when we're faced with lots of quick requests.
- Maybe it is just a single executor being used rather than multiple ones. It's not entirely clear from the
asgiref.synccode. If it is only one executor, removing its need may enable daphne to process multiple requests in parallel. We're currently seeing that daphne never exceeds 100% CPU usage while we expect it to do so. Possibly, this is the global lock that we have been looking for.