From 3e500f8231ac8cb6f88cbcb508d65663af24f49a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C5=ABdolfs=20O=C5=A1i=C5=86=C5=A1?= Date: Wed, 29 Jul 2026 16:21:05 +0200 Subject: [PATCH] Dedupe in-flight requests in cached() The cache only stored resolved values, so callers asking for the same key while a request was still in flight each issued their own. The peer selector makes this easy to hit: Source and History render their own Header, so switching tabs while the remote listing loads fires a second copy of a request that takes seconds. Cache the promise instead, evicting it on rejection so failures still retry. --- src/lib/cache.ts | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/src/lib/cache.ts b/src/lib/cache.ts index 4be20b98f..b1950daa9 100644 --- a/src/lib/cache.ts +++ b/src/lib/cache.ts @@ -3,19 +3,20 @@ import { LRUCache } from "lru-cache"; export function cached( f: (...args: Args) => Promise, makeKey: (...args: Args) => string, - options?: LRUCache.Options, + options?: LRUCache.Options }, unknown>, ): (...args: Args) => Promise { const cache = new LRUCache(options || { max: 500 }); - return async function (...args: Args): Promise { + return function (...args: Args): Promise { const key = makeKey(...args); - const cached = cache.get(key); + const hit = cache.get(key); + if (hit !== undefined) return hit.promise; - if (cached === undefined) { - const value = await f(...args); - cache.set(key, { value }); - return value; - } else { - return cached.value; - } + const promise = f(...args); + // Evict on rejection so the next caller can retry with a fresh request. + promise.catch(() => { + cache.delete(key); + }); + cache.set(key, { promise }); + return promise; }; }