Django: cached_db SESSION_ENGINE causes "SessionInterrupted" exception

114 Views Asked by At

Configuration:

  • django 3.2
  • using cached sessions in REDIS
  • Moved from SESSION_ENGINE 'django.contrib.sessions.backends.cache' to 'django.contrib.sessions.backends.cached_db' as suggested in the django documentation "This avoids edge cases caused by unreliable data storage in production."

Now following issues arises from time to time:

When storing some data in the session, django crashes with error "SessionInterrupted The request's session was deleted before the request completed"

Debugging this reveals the following: Since the session has been updated, django tries to save it in the db. But the session there does not exist. Since the session save is done with parameter "force_update" (in django.contrib.sessions.backends.db.py called from django.contrib.sessions.backends.cached_db.py), the update fails and raises an exception leading to this error message.

Session settings:

SESSION_EXPIRE_AT_BROWSER_CLOSE = False
SESSION_COOKIE_AGE = 1209600  # 2 weeks in seconds
SESSION_REMEMBER = True

Questions:

  • So how to solve this?
  • How can the session disappear from the db? (timeout?)
  • Why does the save routine use "force_update=True" (removing this parameter effectively solves the issue in this case)
2

There are 2 best solutions below

0
Davy On

Found the root cause: Seems this is not correct:

SESSION_REMEMBER = True

Needs to be (using allauth):

ACCOUNT_SESSION_REMEMBER = True

This wrong setting caused session cookies to be stored "until browser close", which can be longer than the expire date set in the session store (db).

Then when old sessions are cleared from the db, we run into this issue where a session is referenced from a cookie, but doesn't exist anymore in the db, but still exists in the session cache.

0
Arunabh Das On

For me the issue was fixed by changing the SESSION_ENGINE from

SESSION_ENGINE = "django.contrib.sessions.backends.cache"

to

SESSION_ENGINE = "django.contrib.sessions.backends.signed_cookies"

The SESSION block in settings.py now looks as follow

SESSION_ENGINE = "django.contrib.sessions.backends.signed_cookies"
SESSION_COOKIE_HTTPONLY = True
SESSION_COOKIE_AGE = 60*60*24
SESSION_COOKIE_SECURE = True