Skip to content

reliability: In-memory caches grow unbounded (priceCache, keyCache) #185

@moltboie

Description

@moltboie

Problem

Two in-memory Map caches check TTL on read but never evict stale entries:

priceCache (polygon.ts:29)

const priceCache = new Map<string, { price: number; fetchedAt: number }>();

Keys are ${ticker}:${dateString}. With daily syncs across multiple tickers and date lookups, entries accumulate indefinitely. Old entries (past TTL) are never read again but never deleted.

keyCache (webhook.ts:5)

const keyCache = new Map<string, { key: jose.JWK; fetchedAt: number }>();

Plaid rotates verification keys. Old key IDs will never be used again but entries persist forever.

Impact

  • Low severity in practice (small data per entry, server restarts clear them)
  • But it's unbounded growth in a long-running process — against clean code principles
  • Compare with rate-limit.ts which correctly cleans up stale records on a timer

Fix

Add periodic eviction (like rate-limit's cleanup):

const evictStaleEntries = () => {
  const now = Date.now();
  for (const [key, entry] of priceCache) {
    if (now - entry.fetchedAt >= CACHE_TTL_MS) priceCache.delete(key);
  }
};
setInterval(evictStaleEntries, CACHE_TTL_MS);

Or use a simple LRU approach with a max size cap.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    Status

    Done

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions