Skip to content

refactor(cache): replace unstable_cache with createCachedFetch and redis#2479

Draft
kilo-code-bot[bot] wants to merge 2 commits intomainfrom
replace-unstable-cache-with-redis-cached-fetch
Draft

refactor(cache): replace unstable_cache with createCachedFetch and redis#2479
kilo-code-bot[bot] wants to merge 2 commits intomainfrom
replace-unstable-cache-with-redis-cached-fetch

Conversation

@kilo-code-bot
Copy link
Copy Markdown
Contributor

@kilo-code-bot kilo-code-bot bot commented Apr 15, 2026

Summary

Replaced all 6 remaining uses of unstable_cache across the web app with createCachedFetch combined with redisGet/redisSet.

  • Added createRedisCachedFetch helper to cached-fetch.ts for parameterless caches: checks Redis, falls back to the fetcher, and writes back to Redis only on a fresh fetch.
  • Added getOrCreateRedisCachedFetch for parameterized caches (e.g. per-model or per-user keys) so in-process caching is reused across calls.
  • Updated byok-router.ts, providers/vercel/index.ts, posthog-query.ts, byok/index.ts, api/openrouter/providers/route.ts, and api/openrouter/models/route.ts.

Verification

  • pnpm typecheck passes
  • pnpm lint passes
  • pnpm format run
  • Test DB not available in this environment, so Jest was not executed.

Visual Changes

N/A

Reviewer Notes

Redis keys introduced:

  • byok:supported-models (5 min TTL)
  • vercel:models (1 hour TTL)
  • posthog-query:<name>:<hash> (24 hour TTL)
  • byok:providers:<modelId> (5 min TTL)
  • openrouter:providers (24 hour TTL)
  • openrouter:direct-byok-models:<userId> (1 min TTL)

return [];
}
console.debug(
`[getModelUserByokProviders_cached] found user byok providers for ${modelId}`,
300_000,
[]
);
return get();
.map(ep => VercelUserByokInferenceProviderIdSchema.safeParse(ep.tag).data)
.filter(providerId => providerId !== undefined) ?? [];
if (providers.length === 0) {
console.debug(`[getModelUserByokProviders_cached] no user byok providers for ${modelId}`);
return [];
}
console.debug(
`[getModelUserByokProviders_cached] found user byok providers for ${modelId}`,
Comment thread apps/web/src/lib/cached-fetch.ts Outdated
ttlMs: number,
defaultValue: T
) {
return createCachedFetch(
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

WARNING: This helper now swallows fetch failures and returns the default value

createCachedFetch catches any exception from the inner callback, so a Redis timeout, upstream fetch error, or DB error now resolves to defaultValue instead of propagating. That changes callers like openrouter/providers and listSupportedModels from returning an error to silently serving []/{} on a cold cache, which is a behavior regression from unstable_cache.

return existing as () => Promise<T>;
}
const cached = createRedisCachedFetch(redisKey, fetcher, ttlMs, defaultValue);
redisCacheRegistry.set(redisKey, cached);
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

WARNING: The shared registry grows without bound for parameterized keys

getOrCreateRedisCachedFetch never removes entries from redisCacheRegistry, so every unique user id, model id, or PostHog query hash stays resident for the life of the process. In this PR the helper is used with per-user and per-query keys, so a long-lived server can accumulate an unbounded number of closures even after their TTL has expired.

@kilo-code-bot
Copy link
Copy Markdown
Contributor Author

kilo-code-bot bot commented Apr 15, 2026

Code Review Summary

Status: No Issues Found | Recommendation: Merge

Files Reviewed (7 files)
  • apps/web/src/app/api/openrouter/models/route.ts
  • apps/web/src/app/api/openrouter/providers/route.ts
  • apps/web/src/lib/byok/index.ts
  • apps/web/src/lib/cached-fetch.ts
  • apps/web/src/lib/posthog-query.ts
  • apps/web/src/lib/providers/vercel/index.ts
  • apps/web/src/routers/byok-router.ts

Reviewed by gpt-5.4-20260305 · 147,724 tokens

Comment on lines +14 to +18
return getOrCreateRedisCachedFetch(
`openrouter:direct-byok-models:${userId}`,
() => getDirectByokModelsForUser(userId),
60_000
)();
},
86_400_000
);
return get();
* (both Redis and the fetcher are unavailable) so callers can decide
* whether to fail open or handle the error explicitly.
*/
export function createRedisCachedFetch<T>(
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this feels a bit tricky with more than one instance. we probably want to at least add jitter to the ttlMs right?

@chrarnoldus chrarnoldus marked this pull request as draft April 16, 2026 08:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants