mirror of
https://github.com/GSA/notifications-admin.git
synced 2026-02-06 11:23:48 -05:00
Redis is giving us a big performance boost (it’s roughly halved the median request time on the admin app). Once we’re confident that it’s working properly[1] we can eke out a bit more performance from it by keeping the caches alive for longer. As far as I can tell we’re still using Redis in a very low-volume way[2], so increasing the number of things we’re storing shouldn’t start taxing our Redis server at all. But reducing the number of times we have to hit the API to refresh the cache _should_ result in some performance increase. --- 1. ie we’re not seeing instances of stale caches not being invalidated 2. We have 2.5G of available space in Redis. Here is our current usage: ``` used_memory:7728960 used_memory_human:7.37M used_memory_rss:7728960 used_memory_peak:16563776 used_memory_peak_human:15.79M used_memory_lua:37888 ```
69 lines
2.0 KiB
Python
69 lines
2.0 KiB
Python
import json
|
||
from contextlib import suppress
|
||
from datetime import timedelta
|
||
from functools import wraps
|
||
from inspect import signature
|
||
|
||
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 = client_instance.redis_client.get(redis_key)
|
||
if cached:
|
||
return json.loads(cached.decode('utf-8'))
|
||
api_response = client_method(client_instance, *args, **kwargs)
|
||
client_instance.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):
|
||
redis_key = _make_key(key_format, client_method, args, kwargs)
|
||
client_instance.redis_client.delete(redis_key)
|
||
return client_method(client_instance, *args, **kwargs)
|
||
|
||
return new_client_method
|
||
|
||
return _delete
|