Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Properly closed cache connections at the end of the request.

This only affects the new cache api and not the deprecated get_cache.

Refs #21012
  • Loading branch information...
commit d47f794f8fa05591632b8cad4b134858e7ae140d 1 parent 8adbfdf
@apollo13 apollo13 authored
Showing with 41 additions and 11 deletions.
  1. +22 −10 django/core/cache/__init__.py
  2. +19 −1 tests/cache/tests.py
View
32 django/core/cache/__init__.py
@@ -53,7 +53,12 @@ def get_cache(backend, **kwargs):
"""
warnings.warn("'get_cache' is deprecated in favor of 'caches'.",
PendingDeprecationWarning, stacklevel=2)
- return _create_cache(backend, **kwargs)
+ cache = _create_cache(backend, **kwargs)
+ # Some caches -- python-memcached in particular -- need to do a cleanup at the
+ # end of a request cycle. If not implemented in a particular backend
+ # cache.close is a no-op
+ signals.request_finished.connect(cache.close)
+ return cache
def _create_cache(backend, **kwargs):
@@ -79,12 +84,7 @@ def _create_cache(backend, **kwargs):
except (AttributeError, ImportError, ImproperlyConfigured) as e:
raise InvalidCacheBackendError(
"Could not find backend '%s': %s" % (backend, e))
- cache = backend_cls(location, params)
- # Some caches -- python-memcached in particular -- need to do a cleanup at the
- # end of a request cycle. If not implemented in a particular backend
- # cache.close is a no-op
- signals.request_finished.connect(cache.close)
- return cache
+ return backend_cls(location, params)
class CacheHandler(object):
@@ -98,8 +98,10 @@ def __init__(self):
def __getitem__(self, alias):
try:
- return getattr(self._caches, alias)
+ return self._caches.caches[alias]
except AttributeError:
+ self._caches.caches = {}
+ except KeyError:
pass
if alias not in settings.CACHES:
@@ -108,10 +110,12 @@ def __getitem__(self, alias):
)
cache = _create_cache(alias)
- setattr(self._caches, alias, cache)
-
+ self._caches.caches[alias] = cache
return cache
+ def all(self):
+ return getattr(self._caches, 'caches', {}).values()
+
caches = CacheHandler()
@@ -141,3 +145,11 @@ def __ne__(self, other):
return caches[DEFAULT_CACHE_ALIAS] != other
cache = DefaultCacheProxy()
+
+def close_caches(**kwargs):
+ # Some caches -- python-memcached in particular -- need to do a cleanup at the
+ # end of a request cycle. If not implemented in a particular backend
+ # cache.close is a no-op
+ for cache in caches.all():
+ cache.close()
+signals.request_finished.connect(close_caches)
View
20 tests/cache/tests.py
@@ -203,7 +203,6 @@ def custom_key_func(key, key_prefix, version):
'custom_key2': {'KEY_FUNCTION': 'cache.tests.custom_key_func'},
'cull': {'OPTIONS': {'MAX_ENTRIES': 30}},
'zero_cull': {'OPTIONS': {'CULL_FREQUENCY': 0, 'MAX_ENTRIES': 30}},
- 'other': {'LOCATION': 'other'},
}
@@ -1014,6 +1013,13 @@ def setUp(self):
caches['custom_key2']._cache = cache._cache
caches['custom_key2']._expire_info = cache._expire_info
+ @override_settings(CACHES={
+ 'default': {'BACKEND': 'django.core.cache.backends.locmem.LocMemCache'},
+ 'other': {
+ 'BACKEND': 'django.core.cache.backends.locmem.LocMemCache',
+ 'LOCATION': 'other'
+ },
+ })
def test_multiple_caches(self):
"Check that multiple locmem caches are isolated"
cache.set('value', 42)
@@ -1139,6 +1145,12 @@ def test_custom_key_validation(self):
self.assertEqual(cache.get(key), val)
+@override_settings(
+ CACHES={
+ 'default': {
+ 'BACKEND': 'cache.closeable_cache.CacheClass',
+ }
+ },)
class GetCacheTests(IgnorePendingDeprecationWarningsMixin, TestCase):
def test_simple(self):
@@ -1157,6 +1169,12 @@ def test_simple(self):
self.assertRaises(InvalidCacheBackendError, get_cache, 'does_not_exist')
def test_close(self):
+ from django.core import signals
+ self.assertFalse(cache.closed)
+ signals.request_finished.send(self.__class__)
+ self.assertTrue(cache.closed)
+
+ def test_close_deprecated(self):
from django.core.cache import get_cache
from django.core import signals
cache = get_cache('cache.closeable_cache.CacheClass')
Please sign in to comment.
Something went wrong with that request. Please try again.