Skip to content
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

Improve watcher #125

Merged
merged 9 commits into from
Apr 30, 2024
Merged

Improve watcher #125

merged 9 commits into from
Apr 30, 2024

Conversation

nyarly
Copy link
Collaborator

@nyarly nyarly commented Apr 24, 2024

Expands on #113, fixes the Vim test by debouncing notifications internally (which is easier because we only care about touched paths.)

@nyarly nyarly mentioned this pull request Apr 24, 2024
1 task
that way it’s not passed as $in to the build rule, which broke the nix
invocation.
crossbeam_channel should work as before, there were no functional
changes.

inotify is a major version, so it changes watching behaviour by a bit,
making some of the tests fail.
src/watch.rs Outdated
let (watch_tx, watch_rx) = chan::unbounded();

let filter = Filter {
notify: Watcher::new(ntfy_tx, Config::default())?,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a reason why the new watcher uses a 30s poll interval, as opposed to the 0.1s from before?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we can probably increase it up to 3 seconds to take some pressure off of bigger projects, but 30s would kind of destroy the idea imo.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The duration isn't important. I don't have a problem doing something other than the default config, but:

  • We aren't using Notify's debounce anymore, so that delay isn't in the config
  • I think that everywhere we care about, Notify is using OS level FS events, not polling. Test behavior bears that out.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah, true, I figured out it’s only relevant for the poll backend.

src/lib.rs Outdated Show resolved Hide resolved
src/watch.rs Outdated
logger: logger.clone(),
};

thread::spawn(move || filter.run());
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We shouldn’t just spawn threads and ignore their thread handles

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That was my first instinct but we don't have anything to wait on the thread for (all its results are streamed out), so there's little value to joining.

Once the Watcher gets dropped, its side of the channels are dropped, and the Filter will get those errors (e.g. RecvError) and exit its loop.

In the end, I couldn't find a sensible way to make the captured thread handle not dead code, which is why I ignored it.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Check out the code, I added Async::run_with_stop_signal to kill the event loop on drop.

This function allows us to spawn a cooperative async, which is asked
to stop when the async is dropped.

We don’t add a timeout when waiting in the drop, meaning if the inner
async ignores the channel it might block execution.
src/watch.rs Outdated Show resolved Hide resolved
Based on code by @nyarly, this debounces watch events before filtering
file paths.

`notify_debouncer_full` will do the hard part of making sure spurious
events are sufficiently removed before we match on them. From the
docs:

* Only emits a single Rename event if the rename From and To events can be matched
* Merges multiple Rename events
* Takes Rename events into account and updates paths for events that occurred before the rename event, but which haven't been emitted, yet
* Optionally keeps track of the file system IDs all files and stiches rename events together (FSevents, Windows)
* Emits only one Remove event when deleting a directory (inotify)
* Doesn't emit duplicate create events
* Doesn't emit Modify events after a Create event
@Profpatsch
Copy link
Collaborator

The upstream notify library has a sister library called https://docs.rs/notify-debouncer-full/latest/notify_debouncer_full/ in its newer versions, so I rewrote some of the filter code to use that instead, and it seems to fix the vim test without any need for manual debouncing on our part! PTAL.

`macos_eat_late_notifications` is now less straightforward to
implement, because we separated `Watch` from `Filter` and don’t expose
the filter channel anymore.

So instead let’s pass an optional duration, during which the first
event is dropped.

This somewhat complicates the event loop, but it can’t be helped, I
think??
@Profpatsch
Copy link
Collaborator

Also lol, searching for that macos panic only brings up https://users.rust-lang.org/t/mysterious-panic-in-macos-cargo-test/77997/1

We put every test in a sublogger and add its test name, to aid in
debugging.
MacOS has some delay between any change and when the watcher actually
notices it. So it would always show the creation of foo when we want
to make sure `bar` does not get watched, leading to the test failing.

Instead, filter out every file that is not `/bar` here, which should
be fine.
@nyarly nyarly merged commit a572958 into canon Apr 30, 2024
5 of 6 checks passed
@nyarly nyarly deleted the improve-watcher-2 branch April 30, 2024 16:53
@Profpatsch
Copy link
Collaborator

Actually I think the rename_over_vim test is broken on Linux not mac; we are watching the parent dir, so I’d expect it to notify about the creation of bar! Which is the part that fails on Mac.

@Profpatsch
Copy link
Collaborator

Ah, nvm, it’s not that, it should be filtered out by the path filtering, so not generate an interesting event, which is the correct case. It’s hard to know with the panic unwinding being broken on current MacOS runners … probably relevant to that is rust-lang/rust#113783

I’d just disable the test on macos for now and hope it fixes itself … maybe

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants