Repository navigation
Make watcher shutdown synchronous - #31
Merged
Merged
Conversation
Drop signalled teardown but detached the debouncer thread, so events could still arrive after drop. Signal a shutdown flag, drop the watcher, then join.
Merged
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes the intermittent
Test (macos-latest, stable)failure seen on #30:The bug
FileWatcherHandleheld_debouncer_thread: JoinHandle<()>. Dropping aJoinHandledetaches the thread rather than joining it, sodrop(handle)only started teardown. The test's fixed 50 ms settling sleep was the only
thing between that and the next write — with the debounce window also 50 ms,
right on the boundary. A loaded runner tips it over.
Why joining alone is not enough
The
notifybackend can briefly outlive its own drop (FSEvents does). In thatwindow the debouncer can reach the flush deadline for an already-pending path
and emit it before it ever observes the channel disconnect. A join would simply
wait through that emission rather than prevent it.
So
Dropnow, in this order:Arc<AtomicBool>shutdown flag — the loop checks it before everyemit, so a pending path is abandoned rather than raced;
notifyclosure holding thedebouncer's input sender (that disconnect is what lets the loop return);
The order is load-bearing and commented: joining before dropping the watcher
would deadlock.
Testing
The sleep-based test was a poor regression guard — I could not make it fail
locally even under CPU contention (40/40 passes), and it still passed 5/5
against the unfixed code once the sleep was removed.
Replaced it with
shutdown_flag_suppresses_due_emissions, which drivesdebouncer_loopdirectly with a zero debounce, so the path is due the instantit is recorded — exactly the race. It asserts both directions: emitted when not
shutting down, abandoned when it is. No sleeps, no filesystem, 0.00s, and
verified to FAIL when the guard is removed.
dropping_handle_stops_eventsalso loses its post-drop settling sleep, sincethe entire point of the fix is that none is needed.