Improve cached_endpoint behavior with sentinel.

This commit is contained in:
voussoir 2021-06-04 17:47:38 -07:00
parent 56ab6636cc
commit 975408227b
No known key found for this signature in database
GPG key ID: 5F7554F8C26DACCB
3 changed files with 19 additions and 4 deletions

View file

@ -4,11 +4,14 @@ import time
from voussoirkit import dotdict
from voussoirkit import passwordy
from voussoirkit import sentinel
import etiquette
from . import jsonify
NOT_CACHED = sentinel.Sentinel('not cached', truthyness=False)
def cached_endpoint(max_age):
'''
The cached_endpoint decorator can be used on slow endpoints that don't need
@ -29,12 +32,19 @@ def cached_endpoint(max_age):
the previous return value (still using 200 or 304 as appropriate for the
client's provided etag).
With max_age=0, the function will be run every time to check if the value
has changed, but if it hasn't changed then we can still send a 304 response,
saving bandwidth.
An example use case would be large-sized data dumps that don't need to be
precisely up to date every time.
'''
if max_age < 0:
raise ValueError(f'max_age should be positive, not {max_age}.')
state = dotdict.DotDict({
'max_age': max_age,
'stored_value': None,
'stored_value': NOT_CACHED,
'stored_etag': None,
'headers': {'ETag': None, 'Cache-Control': f'max-age={max_age}'},
'last_run': 0,
@ -42,7 +52,12 @@ def cached_endpoint(max_age):
def wrapper(function):
def get_value(*args, **kwargs):
if state.max_age and (time.time() - state.last_run) > state.max_age:
can_bail = (
state.stored_value is not NOT_CACHED and
state.max_age != 0 and
(time.time() - state.last_run) < state.max_age
)
if can_bail:
return state.stored_value
value = function(*args, **kwargs)

View file

@ -195,7 +195,7 @@ def post_album_show_in_folder(album_id):
# Album listings ###################################################################################
@site.route('/all_albums.json')
@decorators.cached_endpoint(max_age=0)
@decorators.cached_endpoint(max_age=15)
def get_all_album_names():
all_albums = {album.display_name: album.id for album in common.P.get_albums()}
response = {'albums': all_albums}

View file

@ -99,7 +99,7 @@ def post_tag_remove_synonym(tagname):
# Tag listings #####################################################################################
@site.route('/all_tags.json')
@decorators.cached_endpoint(max_age=0)
@decorators.cached_endpoint(max_age=15)
def get_all_tag_names():
all_tags = list(common.P.get_all_tag_names())
all_synonyms = common.P.get_all_synonyms()