Adds CACHALOT_TIMEOUT.

This commit is contained in:
Bertrand Bordage 2016-09-06 21:57:26 +02:00
parent 762456415a
commit 571e6ec691
4 changed files with 51 additions and 3 deletions

View File

@ -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

View File

@ -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()

View File

@ -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('?'))

View File

@ -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 dont 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 **dont 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) doesnt 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.