diff --git a/src/services/memory/cache.js b/src/services/memory/cache.js index 7d84d8c..5d98a8d 100644 --- a/src/services/memory/cache.js +++ b/src/services/memory/cache.js @@ -91,21 +91,26 @@ export function createMemoryCache(options = {}) { } } - function removeExpired(now = Date.now()) { - for (const [namespaceKey, bucket] of runtimeNamespaces.entries()) { - if (!bucket.events.length) continue; + function expireNamespace(namespaceKey, now) { + const bucket = runtimeNamespaces.get(namespaceKey); + if (!bucket || !bucket.events.length) return; - const originalLength = bucket.events.length; - bucket.events = bucket.events.filter((entry) => entry.expiresAt > now); - const removed = originalLength - bucket.events.length; - if (removed > 0) { - totalRuntimeEvents -= removed; - metrics.runtime_events_expired += removed; - } + const originalLength = bucket.events.length; + bucket.events = bucket.events.filter((entry) => entry.expiresAt > now); + const removed = originalLength - bucket.events.length; + if (removed > 0) { + totalRuntimeEvents -= removed; + metrics.runtime_events_expired += removed; + } - if (bucket.events.length === 0) { - runtimeNamespaces.delete(namespaceKey); - } + if (bucket.events.length === 0) { + runtimeNamespaces.delete(namespaceKey); + } + } + + function expireAllNamespaces(now = Date.now()) { + for (const [namespaceKey] of runtimeNamespaces.entries()) { + expireNamespace(namespaceKey, now); } } @@ -154,11 +159,15 @@ export function createMemoryCache(options = {}) { }, setRuntimeEvent(scope, event, ttlMs = MINUTE_MS) { const now = Date.now(); - removeExpired(now); + const namespaceKey = getNamespaceKey(scope); + + expireNamespace(namespaceKey, now); + if (totalRuntimeEvents >= maxTotalEvents) { + expireAllNamespaces(now); + } const safeTtlMs = Number.isFinite(ttlMs) && ttlMs > 0 ? ttlMs : MINUTE_MS; const expiresAt = now + safeTtlMs; - const namespaceKey = getNamespaceKey(scope); const bucket = runtimeNamespaces.get(namespaceKey) ?? { events: [] }; bucket.events.push({ @@ -182,9 +191,9 @@ export function createMemoryCache(options = {}) { }, getRecentRuntimeEvents(scope, params = {}) { const now = Date.now(); - removeExpired(now); - const namespaceKey = getNamespaceKey(scope); + expireNamespace(namespaceKey, now); + const bucket = runtimeNamespaces.get(namespaceKey); if (!bucket) return [];