mirror of
https://github.com/django/django.git
synced 2025-05-02 05:04:48 +00:00
Fixed #34806 -- Made cached_db session backend resilient to cache write errors.
Co-authored-by: Natalia <124304+nessita@users.noreply.github.com>
This commit is contained in:
parent
6feaad9113
commit
eceb5e2eea
@ -2,12 +2,16 @@
|
|||||||
Cached, database-backed sessions.
|
Cached, database-backed sessions.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
import logging
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.contrib.sessions.backends.db import SessionStore as DBStore
|
from django.contrib.sessions.backends.db import SessionStore as DBStore
|
||||||
from django.core.cache import caches
|
from django.core.cache import caches
|
||||||
|
|
||||||
KEY_PREFIX = "django.contrib.sessions.cached_db"
|
KEY_PREFIX = "django.contrib.sessions.cached_db"
|
||||||
|
|
||||||
|
logger = logging.getLogger("django.contrib.sessions")
|
||||||
|
|
||||||
|
|
||||||
class SessionStore(DBStore):
|
class SessionStore(DBStore):
|
||||||
"""
|
"""
|
||||||
@ -52,7 +56,10 @@ class SessionStore(DBStore):
|
|||||||
|
|
||||||
def save(self, must_create=False):
|
def save(self, must_create=False):
|
||||||
super().save(must_create)
|
super().save(must_create)
|
||||||
|
try:
|
||||||
self._cache.set(self.cache_key, self._session, self.get_expiry_age())
|
self._cache.set(self.cache_key, self._session, self.get_expiry_age())
|
||||||
|
except Exception:
|
||||||
|
logger.exception("Error saving to cache (%s)", self._cache)
|
||||||
|
|
||||||
def delete(self, session_key=None):
|
def delete(self, session_key=None):
|
||||||
super().delete(session_key)
|
super().delete(session_key)
|
||||||
|
@ -286,6 +286,17 @@ Messages to this logger have ``params`` and ``sql`` in their extra context (but
|
|||||||
unlike ``django.db.backends``, not duration). The values have the same meaning
|
unlike ``django.db.backends``, not duration). The values have the same meaning
|
||||||
as explained in :ref:`django-db-logger`.
|
as explained in :ref:`django-db-logger`.
|
||||||
|
|
||||||
|
.. _django-contrib-sessions-logger:
|
||||||
|
|
||||||
|
``django.contrib.sessions``
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
Log messages related to the :doc:`session framework</topics/http/sessions>`.
|
||||||
|
|
||||||
|
* Non-fatal errors occurring when using the
|
||||||
|
:class:`django.contrib.sessions.backends.cached_db.SessionStore` engine are
|
||||||
|
logged as ``ERROR`` messages with the corresponding traceback.
|
||||||
|
|
||||||
Handlers
|
Handlers
|
||||||
--------
|
--------
|
||||||
|
|
||||||
|
@ -115,7 +115,10 @@ Minor features
|
|||||||
:mod:`django.contrib.sessions`
|
:mod:`django.contrib.sessions`
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
* ...
|
* :class:`django.contrib.sessions.backends.cached_db.SessionStore` now handles
|
||||||
|
exceptions when storing session information in the cache, logging proper
|
||||||
|
error messages with their traceback via the newly added
|
||||||
|
:ref:`sessions logger <django-contrib-sessions-logger>`.
|
||||||
|
|
||||||
:mod:`django.contrib.sitemaps`
|
:mod:`django.contrib.sitemaps`
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
@ -76,9 +76,17 @@ Once your cache is configured, you have to choose between a database-backed
|
|||||||
cache or a non-persistent cache.
|
cache or a non-persistent cache.
|
||||||
|
|
||||||
The cached database backend (``cached_db``) uses a write-through cache --
|
The cached database backend (``cached_db``) uses a write-through cache --
|
||||||
session writes are applied to both the cache and the database. Session reads
|
session writes are applied to both the database and cache, in that order. If
|
||||||
use the cache, or the database if the data has been evicted from the cache. To
|
writing to the cache fails, the exception is handled and logged via the
|
||||||
use this backend, set :setting:`SESSION_ENGINE` to
|
:ref:`sessions logger <django-contrib-sessions-logger>`, to avoid failing an
|
||||||
|
otherwise successful write operation.
|
||||||
|
|
||||||
|
.. versionchanged:: 5.1
|
||||||
|
|
||||||
|
Handling and logging of exceptions when writing to the cache was added.
|
||||||
|
|
||||||
|
Session reads use the cache, or the database if the data has been evicted from
|
||||||
|
the cache. To use this backend, set :setting:`SESSION_ENGINE` to
|
||||||
``"django.contrib.sessions.backends.cached_db"``, and follow the configuration
|
``"django.contrib.sessions.backends.cached_db"``, and follow the configuration
|
||||||
instructions for the `using database-backed sessions`_.
|
instructions for the `using database-backed sessions`_.
|
||||||
|
|
||||||
|
7
tests/cache/failing_cache.py
vendored
Normal file
7
tests/cache/failing_cache.py
vendored
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
from django.core.cache.backends.locmem import LocMemCache
|
||||||
|
|
||||||
|
|
||||||
|
class CacheClass(LocMemCache):
|
||||||
|
|
||||||
|
def set(self, *args, **kwargs):
|
||||||
|
raise Exception("Faked exception saving to cache")
|
@ -517,6 +517,22 @@ class CacheDBSessionTests(SessionTestsMixin, TestCase):
|
|||||||
with self.assertRaises(InvalidCacheBackendError):
|
with self.assertRaises(InvalidCacheBackendError):
|
||||||
self.backend()
|
self.backend()
|
||||||
|
|
||||||
|
@override_settings(
|
||||||
|
CACHES={"default": {"BACKEND": "cache.failing_cache.CacheClass"}}
|
||||||
|
)
|
||||||
|
def test_cache_set_failure_non_fatal(self):
|
||||||
|
"""Failing to write to the cache does not raise errors."""
|
||||||
|
session = self.backend()
|
||||||
|
session["key"] = "val"
|
||||||
|
|
||||||
|
with self.assertLogs("django.contrib.sessions", "ERROR") as cm:
|
||||||
|
session.save()
|
||||||
|
|
||||||
|
# A proper ERROR log message was recorded.
|
||||||
|
log = cm.records[-1]
|
||||||
|
self.assertEqual(log.message, f"Error saving to cache ({session._cache})")
|
||||||
|
self.assertEqual(str(log.exc_info[1]), "Faked exception saving to cache")
|
||||||
|
|
||||||
|
|
||||||
@override_settings(USE_TZ=True)
|
@override_settings(USE_TZ=True)
|
||||||
class CacheDBSessionWithTimeZoneTests(CacheDBSessionTests):
|
class CacheDBSessionWithTimeZoneTests(CacheDBSessionTests):
|
||||||
|
Loading…
x
Reference in New Issue
Block a user