feat(02-01): add comprehensive dispose() to FileWatcher and DataCache
FileWatcher.dispose(): - Calls stop() to close watchers - Clears all timers: retry, debounce, catch-up, polling - Clears all tracking maps: lastProcessedLineCount, lastProcessedSize, activeSessionFiles, polledFileSizes, processingInProgress, pendingReprocess - Calls removeAllListeners() LAST to prevent events during cleanup - Sets disposed flag to prevent reuse DataCache.dispose(): - Clears cache Map - Disables caching - Sets disposed flag to prevent reuse - Auto-cleanup interval managed by caller (ServiceContext) Both services prevent restart after disposal for proper lifecycle management.
This commit is contained in:
parent
777d93f968
commit
767c985947
2 changed files with 95 additions and 0 deletions
|
|
@ -29,6 +29,7 @@ export class DataCache {
|
||||||
private maxSize: number;
|
private maxSize: number;
|
||||||
private ttl: number; // Time-to-live in milliseconds
|
private ttl: number; // Time-to-live in milliseconds
|
||||||
private enabled: boolean; // Whether caching is enabled
|
private enabled: boolean; // Whether caching is enabled
|
||||||
|
private disposed = false; // Flag to prevent reuse after disposal
|
||||||
private static readonly CURRENT_VERSION = 2; // Increment when cache structure changes
|
private static readonly CURRENT_VERSION = 2; // Increment when cache structure changes
|
||||||
|
|
||||||
constructor(maxSize: number = 50, ttlMinutes: number = 10, enabled: boolean = true) {
|
constructor(maxSize: number = 50, ttlMinutes: number = 10, enabled: boolean = true) {
|
||||||
|
|
@ -353,4 +354,32 @@ export class DataCache {
|
||||||
|
|
||||||
return sessionIds;
|
return sessionIds;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Disposes the cache and prevents further use.
|
||||||
|
* Clears all cached data and disables caching.
|
||||||
|
*
|
||||||
|
* Note: The auto-cleanup interval returned by startAutoCleanup() is managed
|
||||||
|
* by the caller (ServiceContext), not stored internally, so we only need to
|
||||||
|
* clear the cache and disable it.
|
||||||
|
*/
|
||||||
|
dispose(): void {
|
||||||
|
if (this.disposed) {
|
||||||
|
logger.info('DataCache already disposed');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.info('Disposing DataCache');
|
||||||
|
|
||||||
|
// Clear all cached data
|
||||||
|
this.cache.clear();
|
||||||
|
|
||||||
|
// Disable caching
|
||||||
|
this.enabled = false;
|
||||||
|
|
||||||
|
// Mark as disposed
|
||||||
|
this.disposed = true;
|
||||||
|
|
||||||
|
logger.info('DataCache disposed');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -80,6 +80,8 @@ export class FileWatcher extends EventEmitter {
|
||||||
private processingInProgress = new Set<string>();
|
private processingInProgress = new Set<string>();
|
||||||
/** Files that need reprocessing after current processing completes */
|
/** Files that need reprocessing after current processing completes */
|
||||||
private pendingReprocess = new Set<string>();
|
private pendingReprocess = new Set<string>();
|
||||||
|
/** Flag to prevent reuse after disposal */
|
||||||
|
private disposed = false;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
dataCache: DataCache,
|
dataCache: DataCache,
|
||||||
|
|
@ -117,6 +119,11 @@ export class FileWatcher extends EventEmitter {
|
||||||
* Starts watching the projects and todos directories.
|
* Starts watching the projects and todos directories.
|
||||||
*/
|
*/
|
||||||
start(): void {
|
start(): void {
|
||||||
|
if (this.disposed) {
|
||||||
|
logger.error('Cannot start disposed FileWatcher');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (this.isWatching) {
|
if (this.isWatching) {
|
||||||
logger.warn('Already watching');
|
logger.warn('Already watching');
|
||||||
return;
|
return;
|
||||||
|
|
@ -181,6 +188,65 @@ export class FileWatcher extends EventEmitter {
|
||||||
logger.info('Stopped watching');
|
logger.info('Stopped watching');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Disposes all resources and prevents reuse.
|
||||||
|
* Performs comprehensive cleanup of all timers, watchers, maps, and listeners.
|
||||||
|
*
|
||||||
|
* After calling dispose(), this FileWatcher cannot be restarted.
|
||||||
|
* Use stop() for temporary pausing that can be resumed with start().
|
||||||
|
*/
|
||||||
|
dispose(): void {
|
||||||
|
if (this.disposed) {
|
||||||
|
logger.warn('FileWatcher already disposed');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.info('Disposing FileWatcher');
|
||||||
|
|
||||||
|
// 1. Stop watchers and clear timers (uses existing stop() logic)
|
||||||
|
this.stop();
|
||||||
|
|
||||||
|
// 2. Clear retry timer (stop() already handles this, but being explicit)
|
||||||
|
if (this.retryTimer) {
|
||||||
|
clearTimeout(this.retryTimer);
|
||||||
|
this.retryTimer = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. Clear all debounce timers (stop() already handles this)
|
||||||
|
for (const timer of this.debounceTimers.values()) {
|
||||||
|
clearTimeout(timer);
|
||||||
|
}
|
||||||
|
this.debounceTimers.clear();
|
||||||
|
|
||||||
|
// 4. Clear catch-up timer (stop() already handles this)
|
||||||
|
if (this.catchUpTimer) {
|
||||||
|
clearInterval(this.catchUpTimer);
|
||||||
|
this.catchUpTimer = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 5. Clear polling timer (stop() already handles this)
|
||||||
|
if (this.pollingTimer) {
|
||||||
|
clearInterval(this.pollingTimer);
|
||||||
|
this.pollingTimer = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 6. Clear all tracking maps (stop() already handles most of these)
|
||||||
|
this.lastProcessedLineCount.clear();
|
||||||
|
this.lastProcessedSize.clear();
|
||||||
|
this.activeSessionFiles.clear();
|
||||||
|
this.polledFileSizes.clear();
|
||||||
|
this.processingInProgress.clear();
|
||||||
|
this.pendingReprocess.clear();
|
||||||
|
|
||||||
|
// 7. Remove all EventEmitter listeners (MUST be last)
|
||||||
|
this.removeAllListeners();
|
||||||
|
|
||||||
|
// 8. Mark as disposed
|
||||||
|
this.disposed = true;
|
||||||
|
|
||||||
|
logger.info('FileWatcher disposed');
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Starts the projects directory watcher.
|
* Starts the projects directory watcher.
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue