Channels render MiddlewareNotUsed unusable
See original GitHub issueI don’t know if this is really a bug, and I needed several hours now to track it down. Please tell me if I just have some misconfig or did not understand basics of channels.
But I think that channels renders middleware - that should be run once - useless. Using django==2.0.7, daphne==2.2.0, channels==2.1.2, Linux/Ubuntu 16.04, Firefox, just setup a simple Django project.
pip install django
pip install django-channels
django-admin startproject one
Create a middleware.py
file:
from django.core.exceptions import MiddlewareNotUsed
class OneMiddleware:
def __init__(self, get_response):
"""One-time configuration and initialization of plugins."""
print('Middleware started.')
raise MiddlewareNotUsed
Now add the line
'one.middleware.OneMiddleware',
to settings.MIDDLEWARE and start it:
cd one
./manage.py migrate
./manage.py runserver
It works: At server start, ‘Middleware started.’ is printed, and with every F5 in the browser nothing more happens in the middleware.
If I now set up channels/routing, which works basically, the “statup-once” effect of my middleware is gone - at every reload of the page, my middleware’s __init__()
is called again.
Is this designed/desired functionality? It breaks the only way you can write startup code for Django that should run once. (AppConfig.ready() is no way, and all other ‘unofficial ways’ neither…)
I expected this middleware to run once since MiddlewareNotUsed
was raised here, as described in the Django docs.
Issue Analytics
- State:
- Created 5 years ago
- Comments:13 (10 by maintainers)
I feel that this issue has much larger implications, beyond just rendering
MiddlewareNotUsed
unusable.In particular, for middleware like whitenoise which performs some fairly heavy work in its
__init__
,channels
’s approach of initializing a newAsgiHandler
for each request (and thus also initializing middleware on each request) is causing serious performance problems for many users. #1121 is a good example of this.@pvanagtmaal’s suggestion would only initialize middleware once, but I’m unsure of the implications of implementing that. (I’m not super acquainted with channels yet)
Besides middleware, are there any other smart ways of performing certain actions once during startup (which the middleware might be able to access the results of, down-the-line)?
Could we perhaps devise a way to load the middleware chain outside of the AsgiHandler (on defining the
ProtocolTypeRouter
) and simply inject it into later instantiations of the AsgiHandler? Or is that totally dumb?The Channels
AsgiHandler
will be removed in the next version (v4). Using Django’s implementation going forward, so this issue no longer applies.