From 571e6ec691a1fa8fa6cb535992d016eafc85b0e6 Mon Sep 17 00:00:00 2001 From: Bertrand Bordage Date: Tue, 6 Sep 2016 21:57:26 +0200 Subject: [PATCH] Adds CACHALOT_TIMEOUT. --- cachalot/monkey_patch.py | 5 +++-- cachalot/settings.py | 1 + cachalot/tests/settings.py | 29 +++++++++++++++++++++++++++++ docs/quickstart.rst | 19 ++++++++++++++++++- 4 files changed, 51 insertions(+), 3 deletions(-) diff --git a/cachalot/monkey_patch.py b/cachalot/monkey_patch.py index 07957aa..e3d0e37 100644 --- a/cachalot/monkey_patch.py +++ b/cachalot/monkey_patch.py @@ -42,7 +42,8 @@ def _get_result_or_execute_query(execute_query_func, cache, if new_table_cache_keys: now = time() - cache.set_many({k: now for k in new_table_cache_keys}, None) + cache.set_many({k: now for k in new_table_cache_keys}, + cachalot_settings.CACHALOT_TIMEOUT) elif cache_key in data: timestamp, result = data.pop(cache_key) table_times = data.values() @@ -53,7 +54,7 @@ def _get_result_or_execute_query(execute_query_func, cache, if isinstance(result, Iterable) and result.__class__ not in TUPLE_OR_LIST: result = list(result) - cache.set(cache_key, (time(), result), None) + cache.set(cache_key, (time(), result), cachalot_settings.CACHALOT_TIMEOUT) return result diff --git a/cachalot/settings.py b/cachalot/settings.py index b377d84..63227f7 100644 --- a/cachalot/settings.py +++ b/cachalot/settings.py @@ -4,6 +4,7 @@ from django.conf import settings class Settings(object): CACHALOT_ENABLED = True CACHALOT_CACHE = 'default' + CACHALOT_TIMEOUT = None CACHALOT_CACHE_RANDOM = False CACHALOT_INVALIDATE_RAW = True CACHALOT_ONLY_CACHABLE_TABLES = frozenset() diff --git a/cachalot/tests/settings.py b/cachalot/tests/settings.py index 578306c..cc7e6f7 100644 --- a/cachalot/tests/settings.py +++ b/cachalot/tests/settings.py @@ -1,6 +1,7 @@ # coding: utf-8 from __future__ import unicode_literals +from time import sleep from unittest import skipIf from django.conf import settings @@ -10,6 +11,7 @@ from django.db import connection from django.test import TransactionTestCase from django.test.utils import override_settings +from ..api import invalidate from .models import Test, TestParent, TestChild @@ -82,6 +84,33 @@ class SettingsTestCase(TransactionTestCase): with self.assertNumQueries(0): list(Test.objects.all()) + def test_cache_timeout(self): + with self.assertNumQueries(1): + list(Test.objects.all()) + sleep(1) + with self.assertNumQueries(0): + list(Test.objects.all()) + + invalidate(Test) + + with self.settings(CACHALOT_TIMEOUT=0): + with self.assertNumQueries(1): + list(Test.objects.all()) + sleep(0.05) + with self.assertNumQueries(1): + list(Test.objects.all()) + + # We have to test with a full second and not a shorter time because + # memcached only takes the integer part of the timeout into account. + with self.settings(CACHALOT_TIMEOUT=1): + with self.assertNumQueries(1): + list(Test.objects.all()) + with self.assertNumQueries(0): + list(Test.objects.all()) + sleep(1) + with self.assertNumQueries(1): + list(Test.objects.all()) + def test_cache_random(self): with self.assertNumQueries(1): list(Test.objects.order_by('?')) diff --git a/docs/quickstart.rst b/docs/quickstart.rst index d32febb..2e3650b 100644 --- a/docs/quickstart.rst +++ b/docs/quickstart.rst @@ -61,6 +61,23 @@ Settings .. |CACHES| replace:: ``CACHES`` .. _CACHES: https://docs.djangoproject.com/en/1.7/ref/settings/#std:setting-CACHES +``CACHALOT_TIMEOUT`` +~~~~~~~~~~~~~~~~~~~~ + +:Default: ``None`` +:Description: + Number of seconds during which the cache should consider data as valid. + ``None`` means an infinite timeout. + + .. warning:: + Cache timeouts don’t work in a strict way on most cache backends. + A cache might not keep a cache key during the requested timeout: + it can keep it in memory during a shorter time than the specified timeout. + It can even keep it longer, even if data is not returned when you request it. + So **don’t rely on timeouts to limit the size of your database**, + you might face some unexpected behaviour. + Always set the maximum cache size instead. + ``CACHALOT_CACHE_RANDOM`` ~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -86,7 +103,7 @@ Settings Sequence of SQL table names that will be the only ones django-cachalot will cache. Only queries with a subset of these tables will be cached. The sequence being empty (as it is by default) doesn’t mean that no table - can be cached: it disables this setting, so any table can be cache. + can be cached: it disables this setting, so any table can be cached. :ref:`CACHALOT_UNCACHABLE_TABLES` has more weight than this: if you add a table to both settings, it will never be cached. Use a frozenset over other sequence types for a tiny performance boost.