mirror of
https://github.com/GSA/notifications-admin.git
synced 2026-02-07 03:43:48 -05:00
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.
74 lines
2.1 KiB
Python
74 lines
2.1 KiB
Python
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` doesn’t 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
|