Fall back to inotify when filesystem has errors in fanotify (fix watch in Docker) - #4661
Fall back to inotify when filesystem has errors in fanotify (fix watch in Docker)#4661johnfav03 wants to merge 3 commits into
Conversation
There was a problem hiding this comment.
Pull request overview
Adds automatic inotify fallback when fanotify cannot watch Docker-backed filesystems.
Changes:
- Introduces an unsupported-filesystem sentinel error.
- Tags relevant fanotify failures and switches the watch manager to inotify.
- Adds focused fallback and error-propagation tests.
Reviewed changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated no comments.
Show a summary per file
| File | Description |
|---|---|
internal/fswatch/watcher.go |
Defines the filesystem-support error. |
internal/fswatch/fanotify_linux.go |
Classifies unsupported filesystem errors. |
internal/fswatch/fanotify_linux_test.go |
Tests error classification and propagation. |
internal/execute/watchmanager/watchmanager.go |
Implements backend fallback and watch re-registration. |
internal/execute/watchmanager/watchmanager_fallback_test.go |
Tests fallback behavior and production wiring. |
|
I think this approach is probably okay, though I do wonder if the |
I just made a change embedding the |
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 5 out of 5 changed files in this pull request and generated no new comments.
Suppressed comments (2)
internal/fswatch/watcher.go:266
- This contradicts the PR description's lifecycle claim: the implementation keeps existing fanotify watches and routes only unsupported requests to inotify; it does not have
WatchManagerclose all watches and switch backends. Please update the description (or implement the stated global switch) so the documented behavior matches the code.
func (w *fallbackWatcher) WatchDirectories(requests []WatchDirectoryRequest) ([]Watch, error) {
watches, err := w.primary.WatchDirectories(requests)
if err == nil || !errors.Is(err, ErrFilesystemUnsupported) {
return watches, err
internal/execute/watchmanager/watchmanager.go:281
- If
WatchDirectoriesreturns partial closers together with an error, this success-only branch now drops those live watches without tracking or closing them. The previous implementation explicitly handled that case, andWatchBackenddoes not require failures to be atomic. Please preserve the rollback so a failing reconciliation cannot leak callbacks/resources.
if err == nil {
for i, update := range updates {
entries[i].closer = closers[i]
wm.watchedDirs[update.dir] = entries[i]
}
return nil
Fixes microsoft/TypeScript#63646
Fixes microsoft/TypeScript#63678
Some filesystems, notably Docker bind mounts on macOS and Docker containers' root filesystems, don't implement
name_to_handle_at. This is an issue because we default to fanotify for Linux environments, but in these Docker filesystems everyfanotify_markfails withEOPNOTSUPP, so none of the directory watches are ever registered. This results in the initial build succeeding, but subsequent file changes not being detected.In the fix, when the backend defaults to fanotify and
ReconcileWatchesfails withErrFilesystemUnspported,WatchManagercloses any existing watches, switches to an inotify backend, and re-registers the desired watch set.