Support page-specific cache purging
tomdyson opened this issue · 4 comments
Could clear_cache()
take an optional page argument, supporting page-specific cache purging? It would be great to match the standard behaviour for Wagtail's front-end cache invalidation:
http://docs.wagtail.io/en/latest/reference/contrib/frontendcache.html
Assuming that CacheMiddleware.process_response()
stores the keys based on URL, this should be possible. Will have to research CacheMiddleware more.
Finally figured out how to do this. The Django cache utilities generate cache keys based on a variety of factors, most of which makes it impossible to guess the cache entries for a given page, as the keys contain a combination of request URI (hashed), locale, method, etc.
Now that wagtail-cache is no longer using the django cache middleware, we have a bit more control over the caching process. To be able to purge based on URI alone, and not based on specific locales and request headers, we would need to maintain a separate cache index of keys based on URI. This can be accomplished by storing the cache keys in a list, in a dictionary keyed by URI or something easy to look up.
# Create caches key dict.
if not cache.get('keyring'):
cache.set('keyring', {})
# Process response here, which yields a
cache_key = ...
# Track cache keys.
uri = request.build_absolute_uri()
keyring = cache.get('keyring')
keyring[uri] = keyring.get(uri, []) + [cache_key]
cache.set('keyring', keyring)
From here, to purge and individual page, one would get a list of cache keys from the keyring based on the URI of that page, and then delete those individually.
I have taken the inspiration and expanded it.
Now you can clean up the cache in e.g. wagtail_hooks.py .
EXAMPLE:
@hooks.register('after_create_page')
@hooks.register('after_edit_page')
def clear_wagtailcache(request, page):
purge_cache(
[
page.full_url, # page
page.get_parent().full_url, # category page
page.get_url_parts()[1], # root page
]
)