Only wait for preemptive cache if it's enabled for path & view
This commit is contained in:
parent
599098a589
commit
6499bd160f
3 changed files with 93 additions and 25 deletions
|
|
@ -371,7 +371,9 @@ def cached(timeout=5 * 60, key=lambda: "view:%s" % flask.request.path, unless=No
|
|||
return decorator
|
||||
|
||||
def is_in_cache(key=lambda: "view:%s" % flask.request.path):
|
||||
return key() in _cache
|
||||
if callable(key):
|
||||
key = key()
|
||||
return key in _cache
|
||||
|
||||
def cache_check_headers():
|
||||
return "no-cache" in flask.request.cache_control or "no-cache" in flask.request.pragma
|
||||
|
|
@ -400,10 +402,11 @@ class PreemptiveCache(object):
|
|||
self.cachefile = cachefile
|
||||
|
||||
self._lock = threading.RLock()
|
||||
self._log_lock = threading.RLock()
|
||||
self._logger = logging.getLogger(__name__ + "." + self.__class__.__name__)
|
||||
self._log_access = True
|
||||
|
||||
def record(self, data, unless=None):
|
||||
def record(self, data, unless=None, root=None):
|
||||
if callable(unless) and unless():
|
||||
return
|
||||
|
||||
|
|
@ -412,12 +415,32 @@ class PreemptiveCache(object):
|
|||
entry_data = entry_data()
|
||||
|
||||
if entry_data is not None:
|
||||
if root is None:
|
||||
from flask import request
|
||||
root = request.path
|
||||
self.add_data(root, entry_data)
|
||||
|
||||
def has_record(self, data, root=None):
|
||||
if callable(data):
|
||||
data = data()
|
||||
|
||||
if data is None:
|
||||
return False
|
||||
|
||||
if root is None:
|
||||
from flask import request
|
||||
self.add_data(request.path, entry_data)
|
||||
root = request.path
|
||||
|
||||
all_data = self.get_data(root)
|
||||
for existing in all_data:
|
||||
if self._compare_data(data, existing):
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
@contextlib.contextmanager
|
||||
def disable_access_logging(self):
|
||||
with self._lock:
|
||||
with self._log_lock:
|
||||
self._log_access = False
|
||||
yield
|
||||
self._log_access = True
|
||||
|
|
@ -482,20 +505,19 @@ class PreemptiveCache(object):
|
|||
self.set_all_data(all_data)
|
||||
|
||||
def add_data(self, root, data):
|
||||
from octoprint.util import dict_filter
|
||||
|
||||
def strip_ignored(d):
|
||||
return dict_filter(d, lambda k, v: not k.startswith("_"))
|
||||
|
||||
def compare(a, b):
|
||||
return set(strip_ignored(a).items()) == set(strip_ignored(b).items())
|
||||
with self._log_lock:
|
||||
if not self._log_access:
|
||||
self._logger.debug(
|
||||
"Not updating timestamp and counter for {} and {!r}, currently flagged as disabled".format(root,
|
||||
data))
|
||||
return
|
||||
|
||||
def split_matched_and_unmatched(entry, entries):
|
||||
matched = []
|
||||
unmatched = []
|
||||
|
||||
for e in entries:
|
||||
if compare(e, entry):
|
||||
if self._compare_data(e, entry):
|
||||
matched.append(e)
|
||||
else:
|
||||
unmatched.append(e)
|
||||
|
|
@ -503,12 +525,6 @@ class PreemptiveCache(object):
|
|||
return matched, unmatched
|
||||
|
||||
with self._lock:
|
||||
if not self._log_access:
|
||||
self._logger.debug(
|
||||
"Not updating timestamp and counter for {} and {!r}, currently flagged as disabled".format(root,
|
||||
data))
|
||||
return
|
||||
|
||||
cache_data = self.get_all_data()
|
||||
|
||||
if not root in cache_data:
|
||||
|
|
@ -537,6 +553,14 @@ class PreemptiveCache(object):
|
|||
|
||||
self.set_data(root, [to_persist] + other)
|
||||
|
||||
def _compare_data(self, a, b):
|
||||
from octoprint.util import dict_filter
|
||||
|
||||
def strip_ignored(d):
|
||||
return dict_filter(d, lambda k, v: not k.startswith("_"))
|
||||
|
||||
return set(strip_ignored(a).items()) == set(strip_ignored(b).items())
|
||||
|
||||
|
||||
def preemptively_cached(cache, data, unless=None):
|
||||
def decorator(f):
|
||||
|
|
|
|||
|
|
@ -30,25 +30,63 @@ _logger = logging.getLogger(__name__)
|
|||
_valid_id_re = re.compile("[a-z_]+")
|
||||
_valid_div_re = re.compile("[a-zA-Z_-]+")
|
||||
|
||||
def _preemptive_unless(root=None, path=None):
|
||||
if root is None:
|
||||
root = request.url_root
|
||||
if path is None:
|
||||
path = request.path
|
||||
|
||||
return not settings().getBoolean(["devel", "cache", "preemptive"]) \
|
||||
or path in settings().get(["server", "preemptiveCache", "exceptions"]) \
|
||||
or not (root.startswith("http://") or root.startswith("https://"))
|
||||
|
||||
def _preemptive_data(path=None, base_url=None):
|
||||
if path is None:
|
||||
path = request.path
|
||||
if base_url is None:
|
||||
base_url = request.url_root
|
||||
|
||||
return dict(path=path,
|
||||
base_url=base_url,
|
||||
query_string="l10n={}".format(g.locale.language) if g.locale else "en")
|
||||
|
||||
def _cache_key(url=None, locale=None):
|
||||
if url is None:
|
||||
url = request.base_url
|
||||
if locale is None:
|
||||
locale = g.locale.language if g.locale else "en"
|
||||
|
||||
return "view:{}:{}".format(url, locale)
|
||||
|
||||
@app.route("/cached.gif")
|
||||
def in_cache():
|
||||
url = request.base_url.replace("/cached.gif", "/")
|
||||
key = lambda: "view:{}:{}".format(url, g.locale.language if g.locale else "en")
|
||||
if not util.flask.is_in_cache(key):
|
||||
return abort(404)
|
||||
path = request.path.replace("/cached.gif", "/")
|
||||
|
||||
key = _cache_key(url)
|
||||
data = _preemptive_data(path=path)
|
||||
|
||||
response = make_response(bytes(base64.b64decode("R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7")))
|
||||
response.headers["Content-Type"] = "image/gif"
|
||||
return response
|
||||
|
||||
if _preemptive_unless(root=url, path=path) or not preemptiveCache.has_record(data, root=path):
|
||||
_logger.info("Preemptive cache not active for path {} and data {!r}, signaling as cached".format(path, data))
|
||||
return response
|
||||
elif util.flask.is_in_cache(key):
|
||||
_logger.info("Found path {} in cache (key: {}), signaling as cached".format(path, key))
|
||||
return response
|
||||
else:
|
||||
_logger.info("Path {} not yet cached (key: {}), signaling as missing".format(path, key))
|
||||
return abort(404)
|
||||
|
||||
@app.route("/")
|
||||
@util.flask.preemptively_cached(cache=preemptiveCache,
|
||||
data=lambda: dict(path=request.path, base_url=request.url_root, query_string="l10n={}".format(g.locale.language) if g.locale else "en"),
|
||||
unless=lambda: request.url_root in settings().get(["server", "preemptiveCache", "exceptions"]) or not (request.url_root.startswith("http://") or request.url_root.startswith("https://")))
|
||||
data=_preemptive_data,
|
||||
unless=_preemptive_unless)
|
||||
@util.flask.conditional(lambda: _check_etag_and_lastmodified_for_index(), NOT_MODIFIED)
|
||||
@util.flask.cached(timeout=-1,
|
||||
refreshif=lambda cached: _validate_cache_for_index(cached),
|
||||
key=lambda: "view:{}:{}".format(request.base_url, g.locale.language if g.locale else "en"),
|
||||
key=_cache_key,
|
||||
unless_response=lambda response: util.flask.cache_check_response_headers(response))
|
||||
@util.flask.etagged(lambda _: _compute_etag_for_index())
|
||||
@util.flask.lastmodified(lambda _: _compute_date_for_index())
|
||||
|
|
|
|||
|
|
@ -162,9 +162,15 @@
|
|||
|
||||
var message = window.document.getElementById("message");
|
||||
|
||||
var indexCached = false;
|
||||
var indexCachedCallback = function(result) {
|
||||
if (result == "load") {
|
||||
if (indexCached) {
|
||||
return;
|
||||
}
|
||||
|
||||
// our cached.gif loaded, so the index is cached now, let's reload
|
||||
indexCached = true;
|
||||
message.className = "pulsate1 green";
|
||||
message.innerText = "OctoPrint server ready, reloading page...";
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue