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

Make EventedFileUpdateChecker garbage collectable #40133

Merged

Conversation

jonathanhefner
Copy link
Member

@jonathanhefner jonathanhefner commented Aug 28, 2020

The Listen gem dispatches "file changed" events from a separate thread. This thread holds a reference to the changed callback, and runs until the listener is stopped. Thus, objects that are part of the changed callback's scope cannot be garbage collected until the listener is stopped.

This commit isolates the changed callback and associated scope in an EventedFileUpdateChecker::Core instance. This ensures that the EventedFileUpdateChecker instance can be garbage collected. Additionally, this commit adds a finalizer to the EventedFileUpdateChecker instance, which stops the listener and ensures that the EventedFileUpdateChecker::Core instance can be garbage collected.


This is based on top of #40100.

I split this PR into two commits to make it easier to review. The first commit is a minimal diff to make EventedFileUpdateChecker garbage collectable. The second commit is cleanup that eliminates EventedFileUpdateChecker::PathHelper, instead of fixing its indentation.

Copy link
Contributor

@kaspth kaspth left a comment

Choose a reason for hiding this comment

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

I've only skimmed this and I trust you 🙌💪

When an `EventedFileUpdateChecker` instance detects a watched directory
that previously did not exist, it calls `shutdown!` and then `boot!` to
reinitialize its underlying listener.  Prior to this commit, `shutdown!`
invoked `Listen.stop` which stops **all** listeners, globally.  This
commit changes `shutdown!` to stop the checker's listener only.

Fixes rails#38174.
The Listen gem dispatches "file changed" events from a separate thread.
This thread holds a reference to the `changed` callback, and runs until
the listener is stopped.  Thus, objects that are part of the `changed`
callback's scope cannot be garbage collected until the listener is
stopped.

This commit isolates the `changed` callback and associated scope in an
`EventedFileUpdateChecker::Core` instance.  This ensures that the
`EventedFileUpdateChecker` instance can be garbage collected.
Additionally, this commit adds a finalizer to the
`EventedFileUpdateChecker` instance, which stops the listener and
ensures that the `EventedFileUpdateChecker::Core` instance can be
garbage collected.
Comment on lines +86 to +87
wait # Wait for listener thread to start processing events.
GC.start
Copy link
Member Author

Choose a reason for hiding this comment

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

This test uncovered a race condition in Listen / rb-inotify (see guard/rb-inotify#100) that manifests here as a hang when the finalizer stops the listener. However, I don't think it's likely that a normal application would trigger the race condition, so I think this PR is safe to merge. (I've added a wait here to prevent the test itself from triggering the race condition.)

@jonathanhefner jonathanhefner marked this pull request as ready for review September 26, 2020 22:06
@rafaelfranca rafaelfranca merged commit f8b9150 into rails:master Oct 29, 2020
end
end
def common_path(paths)
paths.map { |path| path.ascend.to_a }.reduce(&:&)&.first
Copy link
Contributor

Choose a reason for hiding this comment

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

Behold the three meditating munks! Bringing offerings of :, ) and . &:&)&. 😄

Copy link
Member Author

Choose a reason for hiding this comment

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

A little bit of Ruby poetry! 😆

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

Successfully merging this pull request may close these issues.

None yet

3 participants