#33533 closed Uncategorized (invalid)
SESSION_SAVE_EVERY_REQUEST = True does not handle parallel requests well if some scenarios
Reported by: | Michael | Owned by: | nobody |
---|---|---|---|
Component: | contrib.sessions | Version: | 4.0 |
Severity: | Normal | Keywords: | |
Cc: | Triage Stage: | Unreviewed | |
Has patch: | no | Needs documentation: | no |
Needs tests: | no | Patch needs improvement: | no |
Easy pickings: | no | UI/UX: | no |
Description (last modified by )
In my project, there are some methods on a custom user model that require the request
to calculate certain values. This simple middleware does the trick:
class AttachRequestToUserMiddleware: """Adds the request to the user object, so session information can be looked up by the custom user model. Must come after django.contrib.auth.middleware.AuthenticationMiddleware which adds the user""" def __init__(self, get_response): self.get_response = get_response def __call__(self, request): request.user.request = request return self.get_response(request)
In production, when there are multiple workers running parrallel by uWSGI, if one has SESSION_SAVE_EVERY_REQUEST = True
, then if one makes async requests from JavaScript (e.g. say a Service Worker caching pages on install), then the way it saves/retrieves sessions on every request fails in many spectacular ways.
Here are some example tracebacks of the many errors raised:
Django Version: 4.0.1 Python Version: 3.8.5 Exception Type: ProgrammingError Exception Value: no results to fetch Exception Location: /home/michael/.venv/project/lib/python3.8/site-packages/django/db/utils.py, line 97, in inner /home/michael/.venv/project/lib/python3.8/site-packages/django/db/utils.py, line 97, in inner return func(*args, **kwargs) Exception Type: RuntimeError Exception Value: generator raised StopIteration /home/michael/.venv/project/lib/python3.8/site-packages/django/contrib/auth/__init__.py, line 60, in _get_user_session_key return get_user_model()._meta.pk.to_python(request.session[SESSION_KEY]) Exception Type: MultipleObjectsReturned Exception Value: get() returned more than one Session -- it returned 2! /home/michael/.venv/project/lib/python3.8/site-packages/django/contrib/sessions/backends/base.py, line 180, in _get_session return self._session_cache /home/michael/.venv/project/lib/python3.8/site-packages/django/core/handlers/exception.py, line 47, in inner response = get_response(request) ./core/accounts/middleware.py, line 33, in __call__ request.user.request = request /home/michael/.venv/project/lib/python3.8/site-packages/django/utils/functional.py, line 278, in __setattr__ self._setup() /home/michael/.venv/project/lib/python3.8/site-packages/django/utils/functional.py, line 384, in _setup self._wrapped = self._setupfunc() /home/michael/.venv/project/lib/python3.8/site-packages/django/contrib/auth/middleware.py, line 25, in <lambda> request.user = SimpleLazyObject(lambda: get_user(request)) /home/michael/.venv/project/lib/python3.8/site-packages/django/contrib/auth/middleware.py, line 11, in get_user request._cached_user = auth.get_user(request) /home/michael/.venv/project/lib/python3.8/site-packages/django/contrib/auth/__init__.py, line 177, in get_user user_id = _get_user_session_key(request) /home/michael/.venv/project/lib/python3.8/site-packages/django/contrib/auth/__init__.py, line 60, in _get_user_session_key return get_user_model()._meta.pk.to_python(request.session[SESSION_KEY]) /home/michael/.venv/project/lib/python3.8/site-packages/django/contrib/sessions/backends/base.py, line 50, in __getitem__ return self._session[key] /home/michael/.venv/project/lib/python3.8/site-packages/django/contrib/sessions/backends/base.py, line 185, in _get_session self._session_cache = self.load() /home/michael/.venv/project/lib/python3.8/site-packages/django/contrib/sessions/backends/db.py, line 43, in load s = self._get_session_from_db() /home/michael/.venv/project/lib/python3.8/site-packages/django/contrib/sessions/backends/db.py, line 32, in _get_session_from_db return self.model.objects.get( /home/michael/.venv/project/lib/python3.8/site-packages/django/db/models/manager.py, line 85, in manager_method return getattr(self.get_queryset(), name)(*args, **kwargs) /home/michael/.venv/project/lib/python3.8/site-packages/django/db/models/query.py, line 443, in get raise self.model.MultipleObjectsReturned(
Change History (5)
follow-ups: 2 3 comment:1 by , 3 years ago
Resolution: | → invalid |
---|---|
Status: | new → closed |
comment:2 by , 3 years ago
Replying to Tim Graham:
See TicketClosingReasons/UseSupportChannels for ways to get help if you cannot debug the issue yourself. Please only use this ticket tracker for reporting confirmed bugs. Thanks!
I actually opened a stack overflow question about a week ago and got no responses, and I think it's due to the fact you can't debug a dictionary lookup, it seems like quite an atomic action. I was hestitant on creating this issue, but after giving it some thought, I suspected it must be a bug not the code, since the code is basically set a key in the session, then read the key. But I will try some of those other channels thanks.
comment:3 by , 3 years ago
Description: | modified (diff) |
---|
Replying to Tim Graham:
See TicketClosingReasons/UseSupportChannels for ways to get help if you cannot debug the issue yourself. Please only use this ticket tracker for reporting confirmed bugs. Thanks!
Hi, I have done some more digging with some help: https://forum.djangoproject.com/t/should-it-be-impossible-for-a-session-dict-to-return-more-than-one-value-for-a-key/12298/13
I think the issue is this: if it receives multiple requests at the same time (I have a service worker that requests many pages at installation so it can cache them), and if SESSION_SAVE_EVERY_REQUEST = True
, then the way it handles session updates it just falls over in many spectacular ways.
My for now my fix is to set SESSION_COOKIE_AGE to over a year, and have SESSION_SAVE_EVERY_REQUEST = False
comment:4 by , 3 years ago
Summary: | Should it be impossible for a session dict to return more than one value for a key? → SESSION_SAVE_EVERY_REQUEST = True does not handle parallel requests well if some scenarios |
---|
comment:5 by , 3 years ago
Description: | modified (diff) |
---|
See TicketClosingReasons/UseSupportChannels for ways to get help if you cannot debug the issue yourself. Please only use this ticket tracker for reporting confirmed bugs. Thanks!