packages/reflex-cache: send redirect to upstream cache on first fetch

This commit is contained in:
Max Headroom 2022-12-18 23:05:29 +01:00
parent 1754841832
commit 226fc6da9a
3 changed files with 36 additions and 26 deletions

View file

@ -10,9 +10,9 @@ class IPFSController:
self.__nix = nixCache self.__nix = nixCache
self.__db = db self.__db = db
def ipfs_fetch_task(self, nar): def ipfs_fetch_task(self, callback, nar, hint=None):
print(f"Downloading NAR: {nar}") print(f"Downloading NAR: {nar}")
code, content = self.__nix.try_all("get", nar) code, _, content = self.__nix.try_all("get", nar, hint)
if code == 200: if code == 200:
upload = {"file": ("FILE", content, "application/octet-stream")} upload = {"file": ("FILE", content, "application/octet-stream")}
try: try:
@ -22,9 +22,12 @@ class IPFSController:
hash = rIpfs.json()["Hash"] hash = rIpfs.json()["Hash"]
print(f"Mapped: {nar} -> /ipfs/{hash}") print(f"Mapped: {nar} -> /ipfs/{hash}")
self.__db.set_path(nar, hash) self.__db.set_path(nar, hash)
callback()
return (nar, 200, hash) return (nar, 200, hash)
except requests.ConnectionError as e: except requests.ConnectionError as e:
print(e) print(e)
callback()
return (nar, 502, False) return (nar, 502, False)
else: else:
callback()
return (nar, code, False) return (nar, code, False)

View file

@ -10,7 +10,7 @@ class NixCacheFetcher:
self.__caches = caches self.__caches = caches
@lru_cache(maxsize=32768) @lru_cache(maxsize=32768)
def __try_all_cached(self, method, path): def __try_all_cached(self, method, path, hint):
fn = ( fn = (
requests.get requests.get
if method == "get" if method == "get"
@ -22,7 +22,13 @@ class NixCacheFetcher:
bestState = 404 bestState = 404
print(f" fetching [{method}] from any cache {path}") print(f" fetching [{method}] from any cache {path}")
for cache in self.__caches: if hint != None:
caches = []
caches.append(hint)
caches.extend(self.__caches)
else:
caches = self.__caches
for cache in caches:
try: try:
rCache = fn(f"{cache}{path}") rCache = fn(f"{cache}{path}")
if rCache.status_code < bestState: if rCache.status_code < bestState:
@ -30,7 +36,7 @@ class NixCacheFetcher:
print(f" {rCache.status_code} - [{method}] {cache}{path}") print(f" {rCache.status_code} - [{method}] {cache}{path}")
if bestState == 200: if bestState == 200:
r = (bestState, rCache.content if method != "head" else False) r = (bestState, cache, rCache.content if method != "head" else False)
if path.endswith(".narinfo"): if path.endswith(".narinfo"):
return r return r
else: else:
@ -40,10 +46,10 @@ class NixCacheFetcher:
# HACK: lru_cache does not cache results if an exception occurs # HACK: lru_cache does not cache results if an exception occurs
# since we don't want to cache empty query results, we make use of this behavior # since we don't want to cache empty query results, we make use of this behavior
raise Uncached((bestState, False)) raise Uncached((bestState, None, False))
def try_all(self, method, path): def try_all(self, method, path, hint=None):
try: try:
return self.__try_all_cached(method, path) return self.__try_all_cached(method, path, hint)
except Uncached as r: except Uncached as r:
return r.args[0] return r.args[0]

View file

@ -27,7 +27,7 @@ class ReflexHTTPServiceHandler(BaseHTTPRequestHandler):
def do_HEAD(self): def do_HEAD(self):
if self.path.endswith(".narinfo"): if self.path.endswith(".narinfo"):
print(f"NAR info request: {self.path}") print(f"NAR info request: {self.path}")
code, content = self._nix.try_all("head", self.path) code, _, content = self._nix.try_all("head", self.path)
self.send_response(code) self.send_response(code)
self.end_headers() self.end_headers()
else: else:
@ -45,6 +45,15 @@ class ReflexHTTPServiceHandler(BaseHTTPRequestHandler):
resultHash = self._db.get_path(self.path) resultHash = self._db.get_path(self.path)
if resultHash == None: if resultHash == None:
code, cache, _ = self._nix.try_all("head", self.path)
if code == 200:
self.send_response(302)
self.send_header("Location", f"{cache}{self.path}")
self.end_headers()
else:
self.send_response(404)
self.end_headers()
return
with self._workSetLock: with self._workSetLock:
found = False found = False
for (itemNar, itemFuture) in self._workSet: for (itemNar, itemFuture) in self._workSet:
@ -58,25 +67,17 @@ class ReflexHTTPServiceHandler(BaseHTTPRequestHandler):
if not found: if not found:
print(f"Creating new IPFS fetch task for {self.path}") print(f"Creating new IPFS fetch task for {self.path}")
def cb():
with self._workSetLock:
try:
self._workSet.remove((self.path, f))
except KeyError:
# already removed
pass
f = self._executor_nar.submit( f = self._executor_nar.submit(
self._ipfs.ipfs_fetch_task, self.path self._ipfs.ipfs_fetch_task, cb, self.path, cache
) )
self._workSet.add((self.path, f)) self._workSet.add((self.path, f))
resultNar, code, resultHash = f.result()
with self._workSetLock:
try:
self._workSet.remove((self.path, f))
except KeyError:
# already removed
pass
else:
code = 200
if code != 200:
self.send_response(code)
self.end_headers()
return return
self.send_response(302) self.send_response(302)
@ -104,7 +105,7 @@ class ReflexHTTPServiceHandler(BaseHTTPRequestHandler):
elif self.path.endswith(".narinfo"): elif self.path.endswith(".narinfo"):
print(f"NAR info request: {self.path}") print(f"NAR info request: {self.path}")
code, content = self._nix.try_all("get", self.path) code, _, content = self._nix.try_all("get", self.path)
self.send_response(code) self.send_response(code)
self.end_headers() self.end_headers()
if code == 200: if code == 200: