Django / Memcached error: The request's session was deleted before the request completed

Django / Memcached error: The request's session was deleted before the request completed

这是完整的错误:请求的会话在请求完成之前被删除。例如,用户可能已在并发请求中注销。

我在使用我的缓存的会话中使用 python-memcached。每隔几天我就会遇到其中一个错误。它由 request.session.save() 上的 UpdateError 抛出。它来自 sessions/middleware.py 中的第 60 行。 99% 的时间一切正常。我在许多不同的 GET 和 POST 请求的 URL 上看到了这个错误。用户报告说他们没有单击注销按钮。他们还报告说这种情况会在登录后 5 分钟发生,因此他们的会话不会过期。一个多月以来,我的缓存中有 0 次驱逐,已经 运行ning 了。如果我 Google 这个错误,看起来以前没有人得到过它。

我认为与 memcached 的连接可能由于某种原因正在关闭。它在本地主机上 运行ning。我唯一一次看到此错误是在我将缓存配置设置为具有 memcached 运行ning 的服务器时,但它没有在该接口上侦听。这将在每个请求上生成这个确切的异常。那么有没有什么方法可以让 memcache 拒绝侦听一两秒钟或丢弃连接?

这是我的设置:

CACHES = {
    'default': {
        'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
        'LOCATION': '127.0.0.1:11211',
        'TIMEOUT': 1209600,  # Two weeks
    },
}

SESSION_SAVE_EVERY_REQUEST = True
SESSION_ENGINE = "django.contrib.sessions.backends.cache"
SESSION_COOKIE_SECURE = CSRF_COOKIE_SECURE = True
SESSION_COOKIE_AGE = 60 * 90  # In 90 minutes

似乎导致此错误的肯定方法是 运行 cache.delete 在 shell 中使用会话密钥,同时请求 运行ning。所以有些东西正在删除缓存键。我不知道它是 Django 还是 Memcached。 Memcached 确实说 STAT evictions 0.

我做了这个中间件来解决这个问题。它似乎已经照顾它。还要检查您的文件描述符限制。

class SLSessionMiddleware(SessionMiddleware):
    """
    Fixes a bug where sessions sometime fail to be set. Catches the error 10 times and gives up.
    """

    def process_response(self, request, response):

        last_exception = None
        for i in range(10):
            try:
                return super().process_response(request, response)
            except Exception as e:
                request.session.cycle_key()
                time.sleep(1)
                last_exception = e

        raise last_exception

当我启用 Django 的 DummyCache 以防止在开发时缓存我的视图时,我也遇到了这个错误(请注意我使用 Redis 作为我的缓存后端)。

请务必在尝试访问您网站的管理员时禁用 DummyCache。

Django 文档给出了您看到错误的原因的提示:

Finally, Django comes with a “dummy” cache that doesn’t actually cache – it just implements the cache interface without doing anything.

我在我的 settings.py 文件中根据我正在处理的内容在这两行之间进行选择。

"BACKEND": 'django.core.cache.backends.dummy.DummyCache' if DEBUG else "django_redis.cache.RedisCache",
"BACKEND": "django_redis.cache.RedisCache",

在我的例子中,我使用 SESSION_ENGINE = 'django.contrib.sessions.backends.cached_db'

当我从备份(loaddata 左右)更新数据时,我在下次访问时看到这个错误。

因此,连同此类操作,有必要删除缓存中的相应条目: cache.del('django.contrib.sessions.cached_dbo27db603b30jabewi7zkwd78b05zq0vf')。 (当然也可以从redis客户端删除)