Files
notifications-admin/app/notify_client/cache.py
Katie Smith 123b769771 Change code order for Redis delete decorator
Before, the delete decorator would delete the keys from Redis and then
we made the request to api to change the data. However, it is possible
that the cache could get re-populated in between these two things
happening, and so would cache outdated data.

This changes the order to send the api request first. We then always
delete the specified keys from Redis. Changing the order of the code in
the decorator changes the order in which the cache keys get deleted, so
the tests have been updated.
2019-07-26 16:29:50 +01:00

74 lines
2.1 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import json
from contextlib import suppress
from datetime import timedelta
from functools import wraps
from inspect import signature
from app.extensions import redis_client
TTL = int(timedelta(days=7).total_seconds())
def _get_argument(argument_name, client_method, args, kwargs):
with suppress(KeyError):
return kwargs[argument_name]
with suppress(ValueError, IndexError):
argument_index = list(signature(client_method).parameters).index(argument_name)
return args[argument_index - 1] # -1 because `args` doesnt include `self`
with suppress(KeyError):
return signature(client_method).parameters[argument_name].default
raise TypeError("{}() takes no argument called '{}'".format(
client_method.__name__, argument_name
))
def _make_key(key_format, client_method, args, kwargs):
return key_format.format(**{
argument_name: _get_argument(argument_name, client_method, args, kwargs)
for argument_name in list(signature(client_method).parameters)
})
def set(key_format):
def _set(client_method):
@wraps(client_method)
def new_client_method(client_instance, *args, **kwargs):
redis_key = _make_key(key_format, client_method, args, kwargs)
cached = redis_client.get(redis_key)
if cached:
return json.loads(cached.decode('utf-8'))
api_response = client_method(client_instance, *args, **kwargs)
redis_client.set(
redis_key,
json.dumps(api_response),
ex=TTL,
)
return api_response
return new_client_method
return _set
def delete(key_format):
def _delete(client_method):
@wraps(client_method)
def new_client_method(client_instance, *args, **kwargs):
try:
api_response = client_method(client_instance, *args, **kwargs)
finally:
redis_key = _make_key(key_format, client_method, args, kwargs)
redis_client.delete(redis_key)
return api_response
return new_client_method
return _delete