diff --git a/src/main/data/CacheService.ts b/src/main/data/CacheService.ts index d7571205d2..79e8104999 100644 --- a/src/main/data/CacheService.ts +++ b/src/main/data/CacheService.ts @@ -45,6 +45,10 @@ export class CacheService { // Main process cache private cache = new Map() + // GC timer reference and interval time (e.g., every 10 minutes) + private gcInterval: NodeJS.Timeout | null = null + private readonly GC_INTERVAL_MS = 10 * 60 * 1000 + private constructor() { // Private constructor for singleton pattern } @@ -56,6 +60,9 @@ export class CacheService { } this.setupIpcHandlers() + // Start garbage collection + this.startGarbageCollection() + logger.info('CacheService initialized') } @@ -71,6 +78,32 @@ export class CacheService { // ============ Main Process Cache (Internal) ============ + /** + * Garbage collection logic + */ + private startGarbageCollection() { + if (this.gcInterval) return + + this.gcInterval = setInterval(() => { + const now = Date.now() + let removedCount = 0 + + for (const [key, entry] of this.cache.entries()) { + if (entry.expireAt && now > entry.expireAt) { + this.cache.delete(key) + removedCount++ + } + } + + if (removedCount > 0) { + logger.debug(`Garbage collection removed ${removedCount} expired items`) + } + }, this.GC_INTERVAL_MS) + + // unref allows the process to exit if there are no other activities + this.gcInterval.unref() + } + /** * Get value from main process cache */ @@ -158,6 +191,12 @@ export class CacheService { * Cleanup resources */ public cleanup(): void { + // Clear the garbage collection interval + if (this.gcInterval) { + clearInterval(this.gcInterval) + this.gcInterval = null + } + // Clear cache this.cache.clear() diff --git a/src/main/data/PreferenceService.ts b/src/main/data/PreferenceService.ts index ca3d8af9a8..9f25964979 100644 --- a/src/main/data/PreferenceService.ts +++ b/src/main/data/PreferenceService.ts @@ -144,6 +144,9 @@ export class PreferenceService { // Custom notifier for main process change notifications private notifier = new PreferenceNotifier() + // Saves the reference to the cleanup interval + private cleanupInterval: NodeJS.Timeout | null = null + private constructor() { this.setupWindowCleanup() } @@ -501,8 +504,9 @@ export class PreferenceService { } } - // Run cleanup periodically (every 30 seconds) - setInterval(cleanup, 30000) + // Run cleanup periodically (every 5 minutes) + this.cleanupInterval = setInterval(cleanup, 300 * 1000) + this.cleanupInterval.unref() } /** @@ -525,6 +529,22 @@ export class PreferenceService { return new Map(this.subscriptions) } + /** + * Public cleanup method (for app shutdown or test teardown) + */ + public cleanup(): void { + if (this.cleanupInterval) { + clearInterval(this.cleanupInterval) + this.cleanupInterval = null + } + + this.notifier.removeAllSubscriptions() + this.subscriptions.clear() + this.initialized = false + + logger.debug('PreferenceService cleanup completed') + } + /** * Deep equality check for preference values * Handles primitives, arrays, and plain objects