From ad19d8fc00deb4bf17d07dcca9e65366e733ce42 Mon Sep 17 00:00:00 2001 From: openhands Date: Fri, 6 Mar 2026 19:11:21 +0000 Subject: [PATCH] fix: Issue #447 remains unresolved: no caching path exists for POST GraphQL requests (#478) Replace setInterval-based eviction with lazy eviction to avoid the no-undef ESLint error (setInterval is not in the allowed globals list). Expired cache entries are now deleted on access rather than via a background timer. Co-Authored-By: Claude Sonnet 4.6 --- services/ponder/src/api/index.ts | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/services/ponder/src/api/index.ts b/services/ponder/src/api/index.ts index bb0c19e..a4d98eb 100644 --- a/services/ponder/src/api/index.ts +++ b/services/ponder/src/api/index.ts @@ -38,16 +38,6 @@ const responseCache = new Map(); // issuing their own. const inFlight = new Map>(); -// Evict expired entries periodically so the cache stays bounded in memory. -const evictInterval = setInterval(() => { - const now = Date.now(); - for (const [k, v] of responseCache) { - if (v.expiresAt <= now) responseCache.delete(k); - } -}, 30_000); -// Don't keep the process alive just for eviction. -(evictInterval as unknown as { unref?: () => void }).unref?.(); - async function graphqlCache(c: Context, next: Next): Promise { if (c.req.method !== 'GET' && c.req.method !== 'POST') return next(); @@ -61,9 +51,13 @@ async function graphqlCache(c: Context, next: Next): Promise { const now = Date.now(); // 1. Cache hit – serve immediately, no DB involved. + // Evict lazily: delete the entry if it has already expired. const hit = responseCache.get(cacheKey); - if (hit && hit.expiresAt > now) { - return c.body(hit.body, 200, { 'Content-Type': 'application/json' }); + if (hit) { + if (hit.expiresAt > now) { + return c.body(hit.body, 200, { 'Content-Type': 'application/json' }); + } + responseCache.delete(cacheKey); } // 2. In-flight coalescing – N concurrent identical queries share one DB hit.