Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/fix caching middleware conflict with 4.2 #3

Open
wants to merge 13 commits into
base: master
Choose a base branch
from
2 changes: 1 addition & 1 deletion fancy_cache/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
from .cache_page import cache_page # NOQA

__version__ = "1.2.1"
__version__ = "1.2.1.8"
23 changes: 20 additions & 3 deletions fancy_cache/memory.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,10 @@ def find_urls(
) -> typing.Generator[
typing.Tuple[str, str, typing.Optional[typing.Dict[str, int]]], None, None
]:
remembered_urls = cache.get(REMEMBERED_URLS_KEY, {})
if USE_MEMCACHED_CAS is True:
remembered_urls = cache._cache.get(REMEMBERED_URLS_KEY, {})
else:
remembered_urls = cache.get(REMEMBERED_URLS_KEY, {})
keys_to_delete = []
if urls:
regexes = _urls_to_regexes(urls)
Expand All @@ -63,9 +66,15 @@ def find_urls(
if not cache.get(cache_key):
if purge:
keys_to_delete.append(url)
if "/clubs/" in url and "/messages/" in url:
LOGGER.info("fancy_cache.memory.find_urls: cache.get not found for messages url %s", url)
continue
if purge:
cache.delete(cache_key)
result = cache.delete(cache_key)
if result:
LOGGER.info("fancy_cache.memory.find_urls: deleted cache entry for url %s", url)
if not result and "/clubs/" in url and "/messages/" in url:
LOGGER.exception("fancy_cache.memory.find_urls: cache.delete not found for messages url %s", url)
keys_to_delete.append(url)
misses_cache_key = "%s__misses" % url
misses_cache_key = md5(misses_cache_key)
Expand All @@ -87,6 +96,14 @@ def find_urls(
deleted = delete_keys_cas(keys_to_delete)
if deleted is True:
return
# CAS uses `cache._cache.get/set` so we need to set the
# REMEMBERED_URLS dict at that location.
# This is because CAS cannot call `BaseCache.make_key` to generate
# the key when it tries to get a cache entry set by `cache.get/set`.
remembered_urls = cache._cache.get(REMEMBERED_URLS_KEY, {})
remembered_urls = delete_keys(keys_to_delete, remembered_urls)
cache._cache.set(REMEMBERED_URLS_KEY, remembered_urls, LONG_TIME)
return

remembered_urls = cache.get(REMEMBERED_URLS_KEY, {})
remembered_urls = delete_keys(keys_to_delete, remembered_urls)
Expand Down Expand Up @@ -121,7 +138,7 @@ def delete_keys(
Helper function to delete `keys_to_delete` from the `remembered_urls` dict.
"""
for url in keys_to_delete:
remembered_urls.pop(url)
remembered_urls.pop(url, None)
misses_cache_key = "%s__misses" % url
hits_cache_key = "%s__hits" % url
cache.delete(misses_cache_key)
Expand Down
23 changes: 14 additions & 9 deletions fancy_cache/middleware.py
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,15 @@ def remember_url(self, request, cache_key: str, timeout: int) -> None:
# Remembered URLs have been successfully saved
# via Memcached CAS.
return
# CAS uses `cache._cache.get/set` so we need to set the
# REMEMBERED_URLS dict at that location.
# This is because CAS cannot call `BaseCache.make_key` to generate
# the key when it tries to get a cache entry set by `cache.get/set`.
remembered_urls = self.cache._cache.get(REMEMBERED_URLS_KEY, {})
remembered_urls = filter_remembered_urls(remembered_urls)
remembered_urls[url] = (cache_key, expiration_time)
self.cache._cache.set(REMEMBERED_URLS_KEY, remembered_urls, LONG_TIME)
return

remembered_urls = self.cache.get(REMEMBERED_URLS_KEY, {})
remembered_urls = filter_remembered_urls(remembered_urls)
Expand All @@ -205,8 +214,11 @@ def _remember_url_cas(

if remembered_urls is None:
# No cache entry; set the cache using `cache.set`.
LOGGER.info("fancy_cache._remember_url_cas: remembered_urls is None")
return False

LOGGER.info("fancy_cache._remember_url_cas: remembered_urls is not None")

remembered_urls = filter_remembered_urls(remembered_urls)

remembered_urls[url] = (cache_key, expiration_time)
Expand All @@ -222,6 +234,8 @@ def _remember_url_cas(
"Django-fancy-cache failed to save using CAS after %s tries.",
tries,
)
if result is True and "/clubs/" in url and "/messages/" in url:
LOGGER.info("fancy_cache._remember_url_cas: Successfully cached and remembered URL %s", url)
return result


Expand Down Expand Up @@ -379,15 +393,6 @@ def __init__(
if cache_alias is None:
cache_alias = DEFAULT_CACHE_ALIAS
self.cache_alias = cache_alias
# TODO: Likely this will cause a conflict with this commit
# in Django 4.1+:
# https://github.com/django/django/commit/3ff7b15bb79f2ee5b7af245c55ae14546243bb77
# The commit uses a @property decorator to set self.cache
# instead of setting it directly as we do in the line below.
# We can likely solve this by simply removing this line,
# but will need to make sure that the library still works for
# older versions of Django that use this `self.cache =` method.
self.cache = caches[self.cache_alias]
except KeyError:
pass

Expand Down
11 changes: 11 additions & 0 deletions fancy_cache/utils.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
import hashlib
import logging
import time
import typing


LOGGER = logging.getLogger(__name__)


def md5(x) -> str:
return hashlib.md5(x.encode("utf-8")).hexdigest()

Expand All @@ -22,4 +26,11 @@ def filter_remembered_urls(
for key, value in remembered_urls.items()
if isinstance(value, tuple) and value[1] > now
}
filtered_urls = [
key
for key, value in remembered_urls.items()
if "/clubs/" in key and "/messages/" in key and isinstance(value, tuple) and value[1] < now
]
LOGGER.info("fancy_cache.filter_remembered_urls: filtering these URLs: %s", filtered_urls)

return remembered_urls