This is an automated email from the ASF dual-hosted git repository.
christine pushed a commit to branch lyftga
in repository https://gitbox.apache.org/repos/asf/incubator-superset.git
The following commit(s) were added to refs/heads/lyftga by this push:
new 51472e9 Improve cache (#7227)
51472e9 is described below
commit 51472e9035ec293d7c7430955ac5b4a16836104c
Author: Beto Dealmeida <[email protected]>
AuthorDate: Tue Apr 9 11:05:44 2019 -0700
Improve cache (#7227)
* Improve cache
* Improve code, add docs
* Simplify flow
* Update docstring
---
superset/utils/decorators.py | 65 ++++++++++++++++++++++++++++----------------
1 file changed, 41 insertions(+), 24 deletions(-)
diff --git a/superset/utils/decorators.py b/superset/utils/decorators.py
index 23b15a5..911ab7f 100644
--- a/superset/utils/decorators.py
+++ b/superset/utils/decorators.py
@@ -47,12 +47,13 @@ def etag_cache(max_age, check_perms=bool):
"""
A decorator for caching views and handling etag conditional requests.
- The decorator caches the response, returning headers for etag and last
- modified. If the client makes a request that matches, the server will
- return a "304 Not Mofified" status.
+ The decorator adds headers to GET requests that help with caching: Last-
+ Modified, Expires and ETag. It also handles conditional requests, when the
+ client send an If-Matches header.
- If no cache is set, the decorator will still set the ETag header, and
- handle conditional requests.
+ If a cache is set, the decorator will cache GET responses, bypassing the
+ dataframe serialization. POST requests will still benefit from the
+ dataframe cache for requests that produce the same SQL.
"""
def decorator(f):
@@ -61,30 +62,46 @@ def etag_cache(max_age, check_perms=bool):
# check if the user can access the resource
check_perms(*args, **kwargs)
- try:
- # build the cache key from the function arguments and any other
- # additional GET arguments (like `form_data`, eg).
- key_args = list(args)
- key_kwargs = kwargs.copy()
- key_kwargs.update(request.args)
- cache_key = wrapper.make_cache_key(f, *key_args, **key_kwargs)
- response = cache.get(cache_key)
- except Exception: # pylint: disable=broad-except
- if app.debug:
- raise
- logging.exception('Exception possibly due to cache backend.')
- response = None
-
- if response is None or request.method == 'POST':
+ # for POST requests we can't set cache headers, use the response
+ # cache nor use conditional requests; this will still use the
+ # dataframe cache in `superset/viz.py`, though.
+ if request.method == 'POST':
+ return f(*args, **kwargs)
+
+ response = None
+ if cache:
+ try:
+ # build the cache key from the function arguments and any
+ # other additional GET arguments (like `form_data`, eg).
+ key_args = list(args)
+ key_kwargs = kwargs.copy()
+ key_kwargs.update(request.args)
+ cache_key = wrapper.make_cache_key(f, *key_args,
**key_kwargs)
+ response = cache.get(cache_key)
+ except Exception: # pylint: disable=broad-except
+ if app.debug:
+ raise
+ logging.exception('Exception possibly due to cache
backend.')
+
+ # if no response was cached, compute it using the wrapped function
+ if response is None:
response = f(*args, **kwargs)
+
+ # add headers for caching: Last Modified, Expires and ETag
response.cache_control.public = True
response.last_modified = datetime.utcnow()
expiration = max_age if max_age != 0 else FAR_FUTURE
- response.expires = response.last_modified +
timedelta(seconds=expiration)
+ response.expires = \
+ response.last_modified + timedelta(seconds=expiration)
response.add_etag()
- try:
- cache.set(cache_key, response, timeout=max_age)
- except Exception: # pylint: disable=broad-except
+
+ # if we have a cache, store the response from the request
+ if cache:
+ try:
+ cache.set(cache_key, response, timeout=max_age)
+ except Exception: # pylint: disable=broad-except
+ if app.debug:
+ raise
logging.exception('Exception possibly due to cache
backend.')
return response.make_conditional(request)