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
This commit is contained in:
parent
8adbfdfcc4
commit
d47f794f8f
|
@ -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 @@ class CacheHandler(object):
|
|||
|
||||
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 @@ class CacheHandler(object):
|
|||
)
|
||||
|
||||
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 @@ class DefaultCacheProxy(object):
|
|||
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)
|
||||
|
|
|
@ -203,7 +203,6 @@ _caches_setting_base = {
|
|||
'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 @@ class LocMemCacheTests(BaseCacheTests, TestCase):
|
|||
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 @@ class CustomCacheKeyValidationTests(TestCase):
|
|||
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 @@ class GetCacheTests(IgnorePendingDeprecationWarningsMixin, TestCase):
|
|||
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')
|
||||
|
|
Loading…
Reference in New Issue