From 101842b0d2b465fc46fb5f8f4db89c0f04963cdc Mon Sep 17 00:00:00 2001 From: "Kamat, Trivikram" <16024985+trivikr@users.noreply.github.com> Date: Tue, 22 Sep 2026 20:30:24 -0700 Subject: [PATCH 1/3] vfs: forward the watchFile listener through RealFSProvider fs.watchFile() on a path served by a real-directory mount dispatches to RealFSProvider.watchFile(), which ignored the supplied listener and registered an empty function instead. The user callback never fired after the file changed, and fs.unwatchFile(path, listener) could not match the anonymous stub, so the stat watcher's poll timer stayed registered and kept the process alive. Accept the listener and pass it through to fs.watchFile() so the callback fires on change and unwatchFile() removes it by identity. Signed-off-by: Kamat, Trivikram <16024985+trivikr@users.noreply.github.com> Assisted-by: opencode --- lib/internal/vfs/providers/real.js | 4 ++-- test/parallel/test-vfs-real-provider-watch.js | 12 ++++++++---- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/lib/internal/vfs/providers/real.js b/lib/internal/vfs/providers/real.js index 2f25f582244c..a3a5d6329a93 100644 --- a/lib/internal/vfs/providers/real.js +++ b/lib/internal/vfs/providers/real.js @@ -632,9 +632,9 @@ class RealFSProvider extends VirtualProvider { return fs.promises.watch(realPath, options); } - watchFile(vfsPath, options) { + watchFile(vfsPath, options, listener) { const realPath = this.#resolvePath(vfsPath); - return fs.watchFile(realPath, options, () => {}); + return fs.watchFile(realPath, options, listener); } unwatchFile(vfsPath, listener) { diff --git a/test/parallel/test-vfs-real-provider-watch.js b/test/parallel/test-vfs-real-provider-watch.js index 056744c5fd0c..090956466c85 100644 --- a/test/parallel/test-vfs-real-provider-watch.js +++ b/test/parallel/test-vfs-real-provider-watch.js @@ -35,10 +35,14 @@ assert.strictEqual(myVfs.provider.supportsWatch, true); await iter.return(); })().then(common.mustCall()); -// watchFile / unwatchFile +// watchFile / unwatchFile: the listener must be forwarded to the real fs +// watcher (not stubbed), fire on change, and be removable by identity. { fs.writeFileSync(path.join(root, 'wf.txt'), 'a'); - const listener = () => {}; - myVfs.watchFile('/wf.txt', { persistent: false }, listener); - myVfs.unwatchFile('/wf.txt', listener); + const listener = common.mustCall(); + myVfs.watchFile('/wf.txt', { interval: 10, persistent: false }, listener); + fs.writeFileSync(path.join(root, 'wf.txt'), 'b'); + setTimeout(() => { + myVfs.unwatchFile('/wf.txt', listener); + }, 50); } From 66bd9fcb80c0e546722550ef179dd310aa3e7337 Mon Sep 17 00:00:00 2001 From: "Kamat, Trivikram" <16024985+trivikr@users.noreply.github.com> Date: Tue, 22 Sep 2026 22:59:13 -0700 Subject: [PATCH 2/3] fixup! vfs: forward the watchFile listener through RealFSProvider --- test/parallel/test-vfs-real-provider-watch.js | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/test/parallel/test-vfs-real-provider-watch.js b/test/parallel/test-vfs-real-provider-watch.js index 090956466c85..978eb26e6305 100644 --- a/test/parallel/test-vfs-real-provider-watch.js +++ b/test/parallel/test-vfs-real-provider-watch.js @@ -41,8 +41,12 @@ assert.strictEqual(myVfs.provider.supportsWatch, true); fs.writeFileSync(path.join(root, 'wf.txt'), 'a'); const listener = common.mustCall(); myVfs.watchFile('/wf.txt', { interval: 10, persistent: false }, listener); - fs.writeFileSync(path.join(root, 'wf.txt'), 'b'); + // uv_fs_poll records the first stat asynchronously as the baseline and + // only reports subsequent changes, so mutate the file only after that + // baseline reflects 'a'; otherwise the change is folded into the baseline + // and the listener never fires. + setTimeout(() => fs.writeFileSync(path.join(root, 'wf.txt'), 'b'), 100); setTimeout(() => { myVfs.unwatchFile('/wf.txt', listener); - }, 50); + }, 500); } From 94018495cbb41bad4a637ec569c39e3bbb2b9508 Mon Sep 17 00:00:00 2001 From: Trivikram Kamat <16024985+trivikr@users.noreply.github.com> Date: Sun, 27 Sep 2026 14:19:59 -0700 Subject: [PATCH 3/3] fixup! vfs: forward the watchFile listener through RealFSProvider --- test/parallel/test-vfs-real-provider-watch.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/test/parallel/test-vfs-real-provider-watch.js b/test/parallel/test-vfs-real-provider-watch.js index 978eb26e6305..d0f30b75233a 100644 --- a/test/parallel/test-vfs-real-provider-watch.js +++ b/test/parallel/test-vfs-real-provider-watch.js @@ -44,8 +44,10 @@ assert.strictEqual(myVfs.provider.supportsWatch, true); // uv_fs_poll records the first stat asynchronously as the baseline and // only reports subsequent changes, so mutate the file only after that // baseline reflects 'a'; otherwise the change is folded into the baseline - // and the listener never fires. - setTimeout(() => fs.writeFileSync(path.join(root, 'wf.txt'), 'b'), 100); + // and the listener never fires. Change the size too, because some + // platforms (e.g. AIX) only report timestamps to the second, so a + // same-size rewrite within that second would look unchanged. + setTimeout(() => fs.writeFileSync(path.join(root, 'wf.txt'), 'bb'), 100); setTimeout(() => { myVfs.unwatchFile('/wf.txt', listener); }, 500);