From 4dbd0ac965eea6567969f9fbea3f2132be97e584 Mon Sep 17 00:00:00 2001 From: Michael Freno Date: Mon, 6 Apr 2026 13:32:46 -0400 Subject: [PATCH] (sidebar)forget redis, better parallization --- bun.lockb | Bin 484420 -> 482086 bytes package.json | 1 - src/components/Bars.tsx | 86 ++++++---- src/env/client.ts | 103 ++++-------- src/lib/performance-tracking.ts | 106 ++++++------ src/server/api/routers/git-activity.ts | 198 ++++++++--------------- src/server/cache.ts | 215 ++++++++----------------- 7 files changed, 274 insertions(+), 435 deletions(-) diff --git a/bun.lockb b/bun.lockb index 69b2fb2da992e088a1ab6f35752f5a827b35f8fb..932f37e7f86a401614286e0065d6f1b1eef666f8 100755 GIT binary patch delta 91796 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 delta 92900 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 OP_AmFr=NxYjQJOvjC%F} diff --git a/package.json b/package.json index 27ad92d..bf87f6f 100644 --- a/package.json +++ b/package.json @@ -55,7 +55,6 @@ "jose": "^6.1.3", "mermaid": "^11.12.2", "motion": "^12.23.26", - "redis": "^5.10.0", "solid-js": "^1.9.5", "solid-tiptap": "^0.8.0", "ua-parser-js": "^2.0.7", diff --git a/src/components/Bars.tsx b/src/components/Bars.tsx index 1a2bb91..d1f0e16 100644 --- a/src/components/Bars.tsx +++ b/src/components/Bars.tsx @@ -46,6 +46,45 @@ interface ContributionDay { count: number; } +interface GitActivityData { + githubCommits: GitCommit[]; + giteaCommits: GitCommit[]; + githubActivity: ContributionDay[]; + giteaActivity: ContributionDay[]; +} + +// Shared fetch promise — whichever instance mounts first starts the fetch; +// the second instance awaits the same Promise instead of firing its own requests. +let gitActivityPromise: Promise | null = null; + +function fetchGitActivity(): Promise { + if (gitActivityPromise) return gitActivityPromise; + + gitActivityPromise = (async () => { + const [ghCommits, gtCommits, ghActivity, gtActivity] = await Promise.all([ + api.gitActivity.getGitHubCommits.query({ limit: 6 }).catch(() => []), + api.gitActivity.getGiteaCommits.query({ limit: 6 }).catch(() => []), + api.gitActivity.getGitHubActivity.query().catch(() => []), + api.gitActivity.getGiteaActivity.query().catch(() => []) + ]); + + const displayedGithubCommits = ghCommits.slice(0, 3); + const githubShas = new Set(displayedGithubCommits.map((c) => c.sha)); + const uniqueGiteaCommits = gtCommits + .filter((commit) => !githubShas.has(commit.sha)) + .slice(0, 3); + + return { + githubCommits: displayedGithubCommits, + giteaCommits: uniqueGiteaCommits, + githubActivity: ghActivity, + giteaActivity: gtActivity + }; + })(); + + return gitActivityPromise; +} + export function RightBarContent() { const { setLeftBarVisible } = useBars(); const [githubCommits, setGithubCommits] = createSignal([]); @@ -66,41 +105,20 @@ export function RightBarContent() { }; onMount(() => { - const fetchData = async () => { - try { - // Fetch more commits to account for deduplication - const [ghCommits, gtCommits, ghActivity, gtActivity] = - await Promise.all([ - api.gitActivity.getGitHubCommits - .query({ limit: 6 }) - .catch(() => []), - api.gitActivity.getGiteaCommits.query({ limit: 6 }).catch(() => []), - api.gitActivity.getGitHubActivity.query().catch(() => []), - api.gitActivity.getGiteaActivity.query().catch(() => []) - ]); - - // Take first 3 from GitHub - const displayedGithubCommits = ghCommits.slice(0, 3); - - // Deduplicate Gitea commits - only against the 3 shown in GitHub section - const githubShas = new Set(displayedGithubCommits.map((c) => c.sha)); - const uniqueGiteaCommits = gtCommits.filter( - (commit) => !githubShas.has(commit.sha) - ); - - setGithubCommits(displayedGithubCommits); - setGiteaCommits(uniqueGiteaCommits.slice(0, 3)); - setGithubActivity(ghActivity); - setGiteaActivity(gtActivity); - } catch (error) { - console.error("Failed to fetch git activity:", error); - } finally { - setLoading(false); - } - }; - setTimeout(() => { - fetchData(); + fetchGitActivity() + .then((data) => { + setGithubCommits(data.githubCommits); + setGiteaCommits(data.giteaCommits); + setGithubActivity(data.githubActivity); + setGiteaActivity(data.giteaActivity); + }) + .catch((error) => { + console.error("Failed to fetch git activity:", error); + }) + .finally(() => { + setLoading(false); + }); }, 0); }); diff --git a/src/env/client.ts b/src/env/client.ts index 68090f9..7081d74 100644 --- a/src/env/client.ts +++ b/src/env/client.ts @@ -1,80 +1,46 @@ -import { z } from "zod"; +export interface ClientEnv { + VITE_DOMAIN: string; + VITE_AWS_BUCKET_STRING: string; + VITE_DOWNLOAD_BUCKET_STRING: string; + VITE_GOOGLE_CLIENT_ID: string; + VITE_GOOGLE_CLIENT_ID_MAGIC_DELVE: string; + VITE_GITHUB_CLIENT_ID: string; + VITE_WEBSOCKET: string; + VITE_INFILL_ENDPOINT: string; +} -const clientEnvSchema = z.object({ - VITE_DOMAIN: z.string().min(1), - VITE_AWS_BUCKET_STRING: z.string().min(1), - VITE_DOWNLOAD_BUCKET_STRING: z.string().min(1), - VITE_GOOGLE_CLIENT_ID: z.string().min(1), - VITE_GOOGLE_CLIENT_ID_MAGIC_DELVE: z.string().min(1), - VITE_GITHUB_CLIENT_ID: z.string().min(1), - VITE_WEBSOCKET: z.string().min(1), - VITE_INFILL_ENDPOINT: z.string().min(1) -}); - -export type ClientEnv = z.infer; +const requiredKeys: (keyof ClientEnv)[] = [ + "VITE_DOMAIN", + "VITE_AWS_BUCKET_STRING", + "VITE_DOWNLOAD_BUCKET_STRING", + "VITE_GOOGLE_CLIENT_ID", + "VITE_GOOGLE_CLIENT_ID_MAGIC_DELVE", + "VITE_GITHUB_CLIENT_ID", + "VITE_WEBSOCKET", + "VITE_INFILL_ENDPOINT" +]; export const validateClientEnv = ( envVars: Record ): ClientEnv => { - try { - return clientEnvSchema.parse(envVars); - } catch (error) { - if (error instanceof z.ZodError) { - const formattedErrors = error.format(); - const missingVars = Object.entries(formattedErrors) - .filter( - ([key, value]) => - key !== "_errors" && - typeof value === "object" && - value._errors?.length > 0 && - value._errors[0] === "Required" - ) - .map(([key, _]) => key); + const missing = requiredKeys.filter( + (key) => !envVars[key] || envVars[key]!.trim() === "" + ); - const invalidVars = Object.entries(formattedErrors) - .filter( - ([key, value]) => - key !== "_errors" && - typeof value === "object" && - value._errors?.length > 0 && - value._errors[0] !== "Required" - ) - .map(([key, value]) => ({ - key, - error: value._errors[0] - })); - - let errorMessage = "Client environment validation failed:\n"; - - if (missingVars.length > 0) { - errorMessage += `Missing required variables: ${missingVars.join(", ")}\n`; - } - - if (invalidVars.length > 0) { - errorMessage += "Invalid values:\n"; - invalidVars.forEach(({ key, error }) => { - errorMessage += ` ${key}: ${error}\n`; - }); - } - - console.error(errorMessage); - throw new Error(errorMessage); - } - console.error( - "Client environment validation failed with unknown error:", - error - ); - throw new Error("Client environment validation failed with unknown error"); + if (missing.length > 0) { + const message = `Client environment validation failed:\nMissing required variables: ${missing.join(", ")}`; + console.error(message); + throw new Error(message); } + + return envVars as unknown as ClientEnv; }; const validateAndExportEnv = (): ClientEnv => { try { const validated = validateClientEnv(import.meta.env); - console.log("✅ Client environment validation successful"); return validated; } catch (error) { - console.error("❌ Client environment validation failed:", error); throw error; } }; @@ -86,14 +52,5 @@ export const isMissingEnvVar = (varName: string): boolean => { }; export const getMissingEnvVars = (): string[] => { - const requiredClientVars = [ - "VITE_DOMAIN", - "VITE_AWS_BUCKET_STRING", - "VITE_GOOGLE_CLIENT_ID", - "VITE_GOOGLE_CLIENT_ID_MAGIC_DELVE", - "VITE_GITHUB_CLIENT_ID", - "VITE_WEBSOCKET" - ]; - - return requiredClientVars.filter((varName) => isMissingEnvVar(varName)); + return requiredKeys.filter((varName) => isMissingEnvVar(varName)); }; diff --git a/src/lib/performance-tracking.ts b/src/lib/performance-tracking.ts index 36a0e97..e2ee102 100644 --- a/src/lib/performance-tracking.ts +++ b/src/lib/performance-tracking.ts @@ -24,66 +24,76 @@ export function initPerformanceTracking() { return; } + const supported = new Set(PerformanceObserver.supportedEntryTypes ?? []); + // Observe LCP - try { - const lcpObserver = new PerformanceObserver((entryList) => { - const entries = entryList.getEntries(); - const lastEntry = entries[entries.length - 1] as any; - metrics.lcp = lastEntry.renderTime || lastEntry.loadTime; - }); - lcpObserver.observe({ type: "largest-contentful-paint", buffered: true }); - } catch (e) { - console.debug("LCP not supported"); + if (supported.has("largest-contentful-paint")) { + try { + const lcpObserver = new PerformanceObserver((entryList) => { + const entries = entryList.getEntries(); + const lastEntry = entries[entries.length - 1] as any; + metrics.lcp = lastEntry.renderTime || lastEntry.loadTime; + }); + lcpObserver.observe({ type: "largest-contentful-paint", buffered: true }); + } catch (e) { + console.debug("LCP observer failed"); + } } // Observe CLS - try { - const clsObserver = new PerformanceObserver((entryList) => { - for (const entry of entryList.getEntries()) { - const layoutShift = entry as any; - if (!layoutShift.hadRecentInput) { - clsValue += layoutShift.value; - clsEntries.push(layoutShift.value); + if (supported.has("layout-shift")) { + try { + const clsObserver = new PerformanceObserver((entryList) => { + for (const entry of entryList.getEntries()) { + const layoutShift = entry as any; + if (!layoutShift.hadRecentInput) { + clsValue += layoutShift.value; + clsEntries.push(layoutShift.value); + } } - } - metrics.cls = clsValue; - }); - clsObserver.observe({ type: "layout-shift", buffered: true }); - } catch (e) { - console.debug("CLS not supported"); + metrics.cls = clsValue; + }); + clsObserver.observe({ type: "layout-shift", buffered: true }); + } catch (e) { + console.debug("CLS observer failed"); + } } // Observe FID - try { - const fidObserver = new PerformanceObserver((entryList) => { - const firstInput = entryList.getEntries()[0] as any; - if (firstInput) { - metrics.fid = firstInput.processingStart - firstInput.startTime; - } - }); - fidObserver.observe({ type: "first-input", buffered: true }); - } catch (e) { - console.debug("FID not supported"); + if (supported.has("first-input")) { + try { + const fidObserver = new PerformanceObserver((entryList) => { + const firstInput = entryList.getEntries()[0] as any; + if (firstInput) { + metrics.fid = firstInput.processingStart - firstInput.startTime; + } + }); + fidObserver.observe({ type: "first-input", buffered: true }); + } catch (e) { + console.debug("FID observer failed"); + } } // Observe INP (event timing) - try { - const interactions: number[] = []; - const inpObserver = new PerformanceObserver((entryList) => { - for (const entry of entryList.getEntries()) { - const eventEntry = entry as any; - if (eventEntry.interactionId) { - interactions.push(eventEntry.duration); - const sorted = [...interactions].sort((a, b) => b - a); - const p98Index = Math.floor(sorted.length * 0.02); - inpValue = sorted[p98Index] || sorted[0] || 0; - metrics.inp = inpValue; + if (supported.has("event")) { + try { + const interactions: number[] = []; + const inpObserver = new PerformanceObserver((entryList) => { + for (const entry of entryList.getEntries()) { + const eventEntry = entry as any; + if (eventEntry.interactionId) { + interactions.push(eventEntry.duration); + const sorted = [...interactions].sort((a, b) => b - a); + const p98Index = Math.floor(sorted.length * 0.02); + inpValue = sorted[p98Index] || sorted[0] || 0; + metrics.inp = inpValue; + } } - } - }); - inpObserver.observe({ type: "event", buffered: true }); - } catch (e) { - console.debug("INP not supported"); + }); + inpObserver.observe({ type: "event", buffered: true }); + } catch (e) { + console.debug("INP observer failed"); + } } // Get navigation timing metrics diff --git a/src/server/api/routers/git-activity.ts b/src/server/api/routers/git-activity.ts index d47169d..eedc0a5 100644 --- a/src/server/api/routers/git-activity.ts +++ b/src/server/api/routers/git-activity.ts @@ -49,73 +49,29 @@ export const gitActivityRouter = createTRPCRouter({ const events = await eventsResponse.json(); const allCommits: GitCommit[] = []; - // Extract push events and fetch commit details + // Extract commits directly from PushEvent payload — no per-commit API calls needed for (const event of events) { if (event.type !== "PushEvent") continue; - if (allCommits.length >= input.limit * 5) break; // Get extra to ensure we have enough + if (allCommits.length >= input.limit) break; const repoName = event.repo.name; - const commitSha = event.payload.head; + const payloadCommits: any[] = event.payload.commits || []; - try { - // Fetch the actual commit details to get the message - const commitResponse = await fetchWithTimeout( - `https://api.github.com/repos/${repoName}/commits/${commitSha}`, - { - headers: { - Authorization: `Bearer ${env.GITHUB_API_TOKEN}`, - Accept: "application/vnd.github.v3+json" - }, - timeout: 5000 - } - ); - - if (commitResponse.ok) { - const commit = await commitResponse.json(); - - // Filter for your commits - if ( - commit.author?.login === "MikeFreno" || - commit.author?.login === "mikefreno" || - commit.commit?.author?.email?.includes("mike") - ) { - allCommits.push({ - sha: commit.sha?.substring(0, 7) || "unknown", - message: - commit.commit?.message?.split("\n")[0] || "No message", - author: - commit.commit?.author?.name || - commit.author?.login || - "Unknown", - date: - commit.commit?.author?.date || new Date().toISOString(), - repo: repoName, - url: `https://github.com/${repoName}/commit/${commit.sha}` - }); - } - } - } catch (error) { - if ( - error instanceof NetworkError || - error instanceof TimeoutError - ) { - console.warn( - `Network error fetching commit ${commitSha} for ${repoName}, skipping` - ); - } else { - console.error( - `Error fetching commit ${commitSha} for ${repoName}:`, - error - ); - } + for (const payloadCommit of payloadCommits) { + if (allCommits.length >= input.limit) break; + allCommits.push({ + sha: payloadCommit.sha?.substring(0, 7) || "unknown", + message: payloadCommit.message?.split("\n")[0] || "No message", + author: payloadCommit.author?.name || "Unknown", + // event.created_at is the push timestamp — close enough to commit date + date: event.created_at || new Date().toISOString(), + repo: repoName, + url: `https://github.com/${repoName}/commit/${payloadCommit.sha}` + }); } } - // Already sorted by event date, but sort again by commit date to be precise - allCommits.sort( - (a, b) => new Date(b.date).getTime() - new Date(a.date).getTime() - ); - + // Events are already in reverse-chronological order return allCommits.slice(0, input.limit); }, { maxStaleMs: CACHE_CONFIG.GIT_ACTIVITY_MAX_STALE_MS } @@ -155,13 +111,11 @@ export const gitActivityRouter = createTRPCRouter({ await checkResponse(reposResponse); const repos = await reposResponse.json(); - const allCommits: GitCommit[] = []; - for (const repo of repos) { - if (allCommits.length >= input.limit * 3) break; // Get extra to sort later - - try { - const commitsResponse = await fetchWithTimeout( + // Fetch commits for all repos in parallel instead of serially + const commitResults = await Promise.allSettled( + repos.map((repo: any) => + fetchWithTimeout( `${env.GITEA_URL}/api/v1/repos/Mike/${repo.name}/commits?limit=5`, { headers: { @@ -170,46 +124,36 @@ export const gitActivityRouter = createTRPCRouter({ }, timeout: 10000 } - ); + ) + .then((res) => (res.ok ? res.json() : [])) + .catch(() => []) + ) + ); - if (commitsResponse.ok) { - const commits = await commitsResponse.json(); - for (const commit of commits) { - if ( - (commit.commit?.author?.email && - commit.commit.author.email.includes( - "michael@freno.me" - )) || - commit.commit.author.email.includes( - "michaelt.freno@gmail.com" - ) // Filter for your commits - ) { - allCommits.push({ - sha: commit.sha?.substring(0, 7) || "unknown", - message: - commit.commit?.message?.split("\n")[0] || "No message", - author: commit.commit?.author?.name || repo.owner.login, - date: - commit.commit?.author?.date || new Date().toISOString(), - repo: repo.full_name, - url: `${env.GITEA_URL}/${repo.full_name}/commit/${commit.sha}` - }); - } - } - } - } catch (error) { + const allCommits: GitCommit[] = []; + for (let i = 0; i < commitResults.length; i++) { + const result = commitResults[i]; + if (result.status === "rejected") continue; + const repo = repos[i]; + const commits: any[] = result.value; + for (const commit of commits) { + const email: string = commit.commit?.author?.email ?? ""; if ( - error instanceof NetworkError || - error instanceof TimeoutError + email.includes("michael@freno.me") || + email.includes("michaelt.freno@gmail.com") ) { - console.warn( - `Network error fetching commits for ${repo.name}, skipping` - ); - } else { - console.error( - `Error fetching commits for ${repo.name}:`, - error - ); + allCommits.push({ + sha: commit.sha?.substring(0, 7) || "unknown", + message: + commit.commit?.message?.split("\n")[0] || "No message", + author: + commit.commit?.author?.name || + repo.owner?.login || + "Unknown", + date: commit.commit?.author?.date || new Date().toISOString(), + repo: repo.full_name, + url: `${env.GITEA_URL}/${repo.full_name}/commit/${commit.sha}` + }); } } } @@ -336,11 +280,13 @@ export const gitActivityRouter = createTRPCRouter({ const threeMonthsAgo = new Date(); threeMonthsAgo.setMonth(threeMonthsAgo.getMonth() - 3); + const sinceParam = threeMonthsAgo.toISOString(); - for (const repo of repos) { - try { - const commitsResponse = await fetchWithTimeout( - `${env.GITEA_URL}/api/v1/repos/${repo.owner.login}/${repo.name}/commits?limit=100`, + // Fetch commits for all repos in parallel, scoped to the 3-month window + const commitResults = await Promise.allSettled( + repos.map((repo: any) => + fetchWithTimeout( + `${env.GITEA_URL}/api/v1/repos/${repo.owner.login}/${repo.name}/commits?limit=100&since=${sinceParam}`, { headers: { Authorization: `token ${env.GITEA_TOKEN}`, @@ -348,31 +294,23 @@ export const gitActivityRouter = createTRPCRouter({ }, timeout: 10000 } - ); + ) + .then((res) => (res.ok ? res.json() : [])) + .catch(() => []) + ) + ); - if (commitsResponse.ok) { - const commits = await commitsResponse.json(); - for (const commit of commits) { - const date = new Date(commit.commit.author.date) - .toISOString() - .split("T")[0]; - contributionsByDay.set( - date, - (contributionsByDay.get(date) || 0) + 1 - ); - } - } - } catch (error) { - if ( - error instanceof NetworkError || - error instanceof TimeoutError - ) { - console.warn( - `Network error fetching commits for ${repo.name}, skipping` - ); - } else { - console.error(`Error fetching commits for ${repo.name}:`, error); - } + for (const result of commitResults) { + if (result.status === "rejected") continue; + const commits: any[] = result.value; + for (const commit of commits) { + const date = new Date(commit.commit.author.date) + .toISOString() + .split("T")[0]; + contributionsByDay.set( + date, + (contributionsByDay.get(date) || 0) + 1 + ); } } diff --git a/src/server/cache.ts b/src/server/cache.ts index 6e35268..87aa3c9 100644 --- a/src/server/cache.ts +++ b/src/server/cache.ts @@ -1,167 +1,89 @@ /** - * Redis-backed Cache for Serverless + * In-memory cache with TTL * - * Uses Redis for persistent caching across serverless invocations. - * Redis provides: - * - Fast in-memory storage - * - Built-in TTL expiration (automatic cleanup) - * - Persistence across function invocations - * - Native support in Vercel and other platforms + * Redis was replaced because on a low-traffic site the cache TTL almost always + * expires between visits, so every request paid Redis connection + round-trip + * overhead with no benefit. A module-level Map has zero network latency: + * cache hits are a single dictionary lookup, misses fall through immediately. */ -import { createClient } from "redis"; -import { env } from "~/env/server"; import { CACHE_CONFIG } from "~/config"; -let redisClient: ReturnType | null = null; -let isConnecting = false; -let connectionError: Error | null = null; - -/** - * Get or create Redis client (singleton pattern) - */ -async function getRedisClient() { - if (redisClient && redisClient.isOpen) { - return redisClient; - } - - if (isConnecting) { - // Wait for existing connection attempt - await new Promise((resolve) => setTimeout(resolve, 100)); - return getRedisClient(); - } - - if (connectionError) { - throw connectionError; - } - - try { - isConnecting = true; - redisClient = createClient({ url: env.REDIS_URL }); - - redisClient.on("error", (err) => { - console.error("Redis Client Error:", err); - connectionError = err; - }); - - await redisClient.connect(); - isConnecting = false; - connectionError = null; - return redisClient; - } catch (error) { - isConnecting = false; - connectionError = error as Error; - console.error("Failed to connect to Redis:", error); - throw error; - } +interface CacheEntry { + data: T; + /** Absolute timestamp (ms) after which this entry is considered stale */ + expiresAt: number; + /** Absolute timestamp (ms) after which stale fallback is also discarded */ + staleExpiresAt: number; } -/** - * Redis-backed cache interface - */ +// eslint-disable-next-line @typescript-eslint/no-explicit-any +const store = new Map>(); + export const cache = { - async get(key: string): Promise { - try { - const client = await getRedisClient(); - const value = await client.get(key); + get(key: string): T | null { + const entry = store.get(key) as CacheEntry | undefined; + if (!entry) return null; + if (Date.now() > entry.expiresAt) return null; + return entry.data; + }, - if (!value) { - return null; - } + set(key: string, data: T, ttlMs: number): void { + const existing = store.get(key); + store.set(key, { + data, + expiresAt: Date.now() + ttlMs, + // Preserve an existing stale expiry if it's longer, otherwise default + staleExpiresAt: + existing?.staleExpiresAt ?? Date.now() + CACHE_CONFIG.MAX_STALE_DATA_MS + }); + }, - return JSON.parse(value) as T; - } catch (error) { - console.error(`Cache get error for key "${key}":`, error); - return null; + delete(key: string): void { + store.delete(key); + }, + + deleteByPrefix(prefix: string): void { + for (const key of store.keys()) { + if (key.startsWith(prefix)) store.delete(key); } }, - async set(key: string, data: T, ttlMs: number): Promise { - try { - const client = await getRedisClient(); - const value = JSON.stringify(data); - - // Redis SET with EX (expiry in seconds) - await client.set(key, value, { - EX: Math.ceil(ttlMs / 1000) - }); - } catch (error) { - console.error(`Cache set error for key "${key}":`, error); - } + clear(): void { + store.clear(); }, - async delete(key: string): Promise { - try { - const client = await getRedisClient(); - await client.del(key); - } catch (error) { - console.error(`Cache delete error for key "${key}":`, error); - } - }, - - async deleteByPrefix(prefix: string): Promise { - try { - const client = await getRedisClient(); - const keys = await client.keys(`${prefix}*`); - - if (keys.length > 0) { - await client.del(keys); - } - } catch (error) { - console.error( - `Cache deleteByPrefix error for prefix "${prefix}":`, - error - ); - } - }, - - async clear(): Promise { - try { - const client = await getRedisClient(); - await client.flushDb(); - } catch (error) { - console.error("Cache clear error:", error); - } - }, - - async has(key: string): Promise { - try { - const client = await getRedisClient(); - const exists = await client.exists(key); - return exists === 1; - } catch (error) { - console.error(`Cache has error for key "${key}":`, error); - return false; - } + has(key: string): boolean { + const entry = store.get(key); + if (!entry) return false; + return Date.now() <= entry.expiresAt; } }; /** - * Execute function with Redis caching + * Execute function with in-memory caching. */ export async function withCache( key: string, ttlMs: number, fn: () => Promise ): Promise { - const cached = await cache.get(key); - if (cached !== null) { - return cached; - } + const cached = cache.get(key); + if (cached !== null) return cached; const result = await fn(); - await cache.set(key, result, ttlMs); + cache.set(key, result, ttlMs); return result; } /** - * Execute function with Redis caching and stale data fallback + * Execute function with caching and stale-data fallback. * * Strategy: - * 1. Try to get fresh cached data (within TTL) - * 2. If not found, execute function - * 3. If function fails, try to get stale data (ignore TTL) - * 4. Store result with TTL for future requests + * 1. Return data if fresh (within TTL). + * 2. Otherwise run fn(). + * 3. If fn() throws, return stale data if still within maxStaleMs. + * 4. Store fresh result for future requests. */ export async function withCacheAndStale( key: string, @@ -175,34 +97,29 @@ export async function withCacheAndStale( const { maxStaleMs = CACHE_CONFIG.MAX_STALE_DATA_MS, logErrors = true } = options; - // Try fresh cache - const cached = await cache.get(key); - if (cached !== null) { - return cached; - } + const now = Date.now(); + const entry = store.get(key) as CacheEntry | undefined; + + // Fresh hit + if (entry && entry.expiresAt > now) return entry.data; try { - // Execute function const result = await fn(); - await cache.set(key, result, ttlMs); - // Also store with longer TTL for stale fallback - const staleKey = `${key}:stale`; - await cache.set(staleKey, result, maxStaleMs); + store.set(key, { + data: result, + expiresAt: now + ttlMs, + staleExpiresAt: now + maxStaleMs + }); return result; } catch (error) { if (logErrors) { console.error(`Error fetching data for cache key "${key}":`, error); } - // Try stale cache with longer TTL key - const staleKey = `${key}:stale`; - const staleData = await cache.get(staleKey); - - if (staleData !== null) { - if (logErrors) { - console.log(`Serving stale data for cache key "${key}"`); - } - return staleData; + // Stale fallback + if (entry && entry.staleExpiresAt > now) { + if (logErrors) console.log(`Serving stale data for cache key "${key}"`); + return entry.data; } throw error;