From 16d2e1a97ec9ba435a682b91c84b88d4e87bfd95 Mon Sep 17 00:00:00 2001 From: David Snelling Date: Fri, 28 Aug 2026 11:30:00 -0700 Subject: [PATCH] fix(storage): the flush watcher cannot arm twice in its async window MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Arming is asynchronous — the request directory is created before it can be watched — so during that window neither the watcher nor the sweep interval exists yet and the guard let a second call through, leaving two watchers and two sweeps for the life of the store. The callback is the flag that covers the window. --- src/storage/adapters/fileSystemStorage.ts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/storage/adapters/fileSystemStorage.ts b/src/storage/adapters/fileSystemStorage.ts index 9d04b46d..fa0715df 100644 --- a/src/storage/adapters/fileSystemStorage.ts +++ b/src/storage/adapters/fileSystemStorage.ts @@ -2432,7 +2432,12 @@ export class FileSystemStorage extends BaseStorage { * an inspector whose request is never seen waits forever. */ public override startFlushRequestWatcher(onRequest: () => Promise): void { - if (this.flushWatcherInterval || this.flushWatcher) return // already watching + // Already watching — or already ARMING. The arm is asynchronous (the + // request directory is created before it can be watched), so neither the + // watcher nor the interval exists yet during that window; the callback is + // the flag that covers it. Without this a second call in the window would + // leave two watchers and two sweeps running for the life of the store. + if (this.flushWatcherInterval || this.flushWatcher || this.flushWatcherOnRequest) return this.flushWatcherOnRequest = onRequest const reqDir = path.join(this.lockDir, FileSystemStorage.FLUSH_REQUEST_DIR)