Skip to content

Commit be578e3

Browse files
committed
fix(usage-bar): evict oldest template cache entry when size exceeds limit
The module-level fileCache Map grows without bound and holds a live fs.watch watcher for each cached template file. Evict the oldest entry (closing its watcher) when the cache reaches MAX_FILE_CACHE_SIZE (64) so long-running gateways do not accumulate unused watchers. Fixes #98960
1 parent 2e049f5 commit be578e3

1 file changed

Lines changed: 11 additions & 0 deletions

File tree

src/auto-reply/usage-bar/template.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import type { UsageBarTemplate } from "./translator.js";
88
export type UsageTemplateConfig = string | Record<string, unknown> | undefined;
99

1010
type CacheEntry = { template: UsageBarTemplate | undefined; watcher?: FSWatcher };
11+
const MAX_FILE_CACHE_SIZE = 64;
1112
const fileCache = new Map<string, CacheEntry>();
1213
const warnedTemplateOverrides = new Set<string>();
1314
const usageTemplateLog = createSubsystemLogger("usage-template");
@@ -143,6 +144,16 @@ function cacheTemplateFile(path: string): UsageBarTemplate | undefined {
143144
// Cache remains valid without live refresh.
144145
}
145146
}
147+
// Evict oldest entry when cache exceeds the limit so the Map and its live
148+
// fs.watch watchers do not grow without bound across long-running gateways.
149+
if (fileCache.size >= MAX_FILE_CACHE_SIZE) {
150+
const oldestKey = fileCache.keys().next().value;
151+
if (oldestKey !== undefined) {
152+
const oldest = fileCache.get(oldestKey);
153+
oldest?.watcher?.close();
154+
fileCache.delete(oldestKey);
155+
}
156+
}
146157
fileCache.set(path, entry);
147158
return entry.template;
148159
}

0 commit comments

Comments
 (0)