-
Notifications
You must be signed in to change notification settings - Fork 29.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Node 20 recursive file watching is misbehaving on Linux #48437
Comments
Does the issue resolve if you add a small timeout before writing file and after creating the watcher? I suspect the async nature of fs which does polling causes this issue. |
Looks like that did help - https://github.com/cjihrig/recursive-watcher-bug/actions/runs/5247088842/jobs/9476792611. I don't think we can realistically ask every user of recursive file watching to add that to their code though. |
@cjihrig I agree. It seems the issue is within this lines: https://github.com/nodejs/node/blob/main/lib/internal/fs/recursive_watch.js#L222 We can avoid using promisify, but I'm suspicious towards blocking the main thread while this is resolving. Unfortunately, I'm on parental leave and have limited access. If this task is not urgent, I can take a look at it in a week and a half. |
Can I take on this issue? |
Please do. Happy to help if you get stuck on something. |
So the traverse function doesn't complete its execution before the files start to be watched, thus causing a race condition? Would introducing a mechanism to 'await' the initialization of the watcher could resolve this issue? |
That would be a breaking change since it will cause the function to behave differently in different operating systems. |
Understood. Would it be feasible to implement a flag/event that is set once the traverse function has completed? This way, we could delay file watching until after the initial traversal? |
Regarding the race condition issue in the code you shared, I've analyzed it and come up with a solution. The problem arises from the I propose the following solution to address this issue: `async function traverse(dir, files = new SafeMap(), symbolicLinks = new SafeSet()) { const filenames = await opendir(dir); for await (const file of filenames) {
} await Promise.all(subdirectories); // Wait for all subdirectory promises to resolve return files; // ... async kFSWatchStart { try {
} catch (error) { Here are the changes made and their explanations: 1.Modified the traverse function to be an async function and added the await keyword before the recursive call to traverse for subdirectories. This ensures that the function waits for the subdirectory traversal to complete before moving on, resolving the race condition. 2.In the [kFSWatchStart] method, added the await keyword before calling traverse for the initial directory. This ensures that the function waits for the traversal to complete before proceeding with watching the files. |
@spacesugam are you still interested in sending a PR? I would go for the first option. |
@anonrig @cjihrig I took another look at this issue, and there is a race condition between traversing the file system asynchronously and This is not a problem on Windows or Mac because they have different low-level primitives for watching |
The only solution to this bug is to move the exploration of the directory tree to synchronous on Linux. @anonrig do you see any specific issue with that? |
Quite possibly related, calling |
Looks good to me!
@novemberborn Can you create a different issue on this, with a possible reproduction please? |
Version
20.3.0
Platform
linux
Subsystem
fs
What steps will reproduce the bug?
I put together a repro at https://github.com/cjihrig/recursive-watcher-bug that shows the following passing on Windows and macOS, but failing on Ubuntu. I'm not sure if this is specific to GitHub Actions.
How often does it reproduce? Is there a required condition?
Always reproduces for me.
What is the expected behavior? Why is that the expected behavior?
I expect the test to pass.
What do you see instead?
The test times out.
Additional information
I noticed this while trying to update Platformatic to support Node 20 and created the minimal reproduction linked above.
I also noticed that Platformatic was passing
recursive: true
to the promisified version ofwatch()
on Ubuntu on earlier versions of Node. It should have thrownERR_FEATURE_UNAVAILABLE_ON_PLATFORM
, but did not. I did see that error with the callback basedwatch()
though, which makes me think there is some missing validation on older versions of Node in addition to this bug.cc: @anonrig who implemented recursive file watching on Linux.
The text was updated successfully, but these errors were encountered: