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

feat(watcher): add support for poll watcher #21290

Open
wants to merge 4 commits into
base: master
Choose a base branch
from

Conversation

amribm
Copy link

@amribm amribm commented Sep 13, 2024

Closes #21111

@amribm amribm requested a review from a team as a code owner September 13, 2024 04:59
@bits-bot
Copy link

bits-bot commented Sep 13, 2024

CLA assistant check
All committers have signed the CLA.

@amribm amribm force-pushed the feature/support_for_poll_watcher branch from 3773b14 to ae66312 Compare September 13, 2024 05:01
@amribm amribm force-pushed the feature/support_for_poll_watcher branch from 4c926d0 to 1802ece Compare September 13, 2024 05:17
@amribm amribm changed the title feat(watcher): add support for poll watcher support feat(watcher): add support for poll watcher Sep 13, 2024
src/app.rs Outdated Show resolved Hide resolved
interval: NonZeroU64,
) -> config::watcher::WatcherConfig {
match method {
WatchConfigMethod::Inotify => config::watcher::WatcherConfig::RecommendedWatcher,
Copy link
Contributor

Choose a reason for hiding this comment

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

Please, take a look into my comment about this in your closed PR

#21258 (comment)

Copy link
Author

@amribm amribm Sep 13, 2024

Choose a reason for hiding this comment

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

Can we put this as Recommended or any thing that comes to ur mind? @jszwedko

Copy link
Contributor

Choose a reason for hiding this comment

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

yes, that would fit

src/config/watcher.rs Outdated Show resolved Hide resolved
src/config/watcher.rs Outdated Show resolved Hide resolved
}
WatcherConfig::PollWatcher(interval) => {
let config =
notify::Config::default().with_poll_interval(Duration::from_secs(*interval));
Copy link
Contributor

Choose a reason for hiding this comment

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

Should we allow the user to specify compare_contents? https://docs.rs/notify/latest/notify/struct.Config.html#method.with_compare_contents
maybe another argument? Im afraid we are adding too much arguments for this though

@jszwedko

Choose a reason for hiding this comment

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

I'd vote against it being user controllable and hope for it to just have a sane default. I can't think of a scenario where I'd wanna toggle it!

Copy link
Contributor

@jorgehermo9 jorgehermo9 Sep 14, 2024

Choose a reason for hiding this comment

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

We found issues in openshift environments where the inotify watcher was constantly triggered and the file contents did not change at all. In this case, we would like to hash the contents to check if it really changed before reloading vector config. I think having sane defaults is good (for example, this would default to false), but there are situations where this is useful

Choose a reason for hiding this comment

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

Would there be a downside to always hashing the changes?

Copy link
Contributor

@jorgehermo9 jorgehermo9 Sep 14, 2024

Choose a reason for hiding this comment

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

Yes, as the docs I pointed states:

By enabling this feature, performance will be significantly impacted as all files will need to be read and hashed at each poll_interval.

I prefer that downside to be opt-in


enum Watcher {
/// recommended watcher for os, usually inotify for linux based systems
RecommendedWatcher(notify::RecommendedWatcher),
Copy link
Contributor

Choose a reason for hiding this comment

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

I think it would be more idiomatic to use only RecommendedWatcher, adding use notify::RecommendedWatcher and the top of the file (as you has before)

Suggested change
RecommendedWatcher(notify::RecommendedWatcher),
RecommendedWatcher(RecommendedWatcher),

My previous suggestion about this was only about the notify::Watcher trait, and because it conflicted with your Watcher enum

Copy link
Author

Choose a reason for hiding this comment

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

Since the Watcher is necessary for use watch method on PollWatcher and RecommendWatcher . removing that makes watch method is not defined error

Copy link
Contributor

Choose a reason for hiding this comment

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

I think you can use notify::RecommendedWatcher and use notify::PollingWatcher, that have nothing related to what you're saying about the Watcher trait. The previous code imported those two structs

and indeed, maybe you need to use notify::Watcher to use the watch method

/// recommended watcher for os, usually inotify for linux based systems
RecommendedWatcher(notify::RecommendedWatcher),
/// poll based watcher. for watching files from NFS.
PollWatcher(notify::PollWatcher),
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
PollWatcher(notify::PollWatcher),
PollWatcher(PollWatcher),

src/config/watcher.rs Outdated Show resolved Hide resolved

fn watch(&mut self, path: &Path, recursive_mode: RecursiveMode) -> Result<(), Error> {
match self {
&mut Watcher::RecommendedWatcher(ref mut watcher) => {
Copy link
Contributor

Choose a reason for hiding this comment

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

I think you can get rid of this (In the other match arm too)

This behaviour was improved a few years ago

Read about it here: https://github.com/rust-lang/rfcs/blob/master/text/2005-match-ergonomics.md

Suggested change
&mut Watcher::RecommendedWatcher(ref mut watcher) => {
Watcher::RecommendedWatcher(watcher) => {

Comment on lines +149 to +163
match watcher_conf {
WatcherConfig::RecommendedWatcher => {
let recommended_watcher = recommended_watcher(sender)?;
let mut watcher = Watcher::RecommendedWatcher(recommended_watcher);
watcher.add_paths(config_paths)?;
Ok((watcher, receiver))
}
WatcherConfig::PollWatcher(interval) => {
let config =
notify::Config::default().with_poll_interval(Duration::from_secs(*interval));
let poll_watcher = notify::PollWatcher::new(sender, config)?;
let mut watcher = Watcher::PollWatcher(poll_watcher);
watcher.add_paths(config_paths)?;
Ok((watcher, receiver))
}
Copy link
Contributor

Choose a reason for hiding this comment

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

I think you can take

    watcher.add_paths(config_paths)?;
            Ok((watcher, receiver))

out of the match branches

Suggested change
match watcher_conf {
WatcherConfig::RecommendedWatcher => {
let recommended_watcher = recommended_watcher(sender)?;
let mut watcher = Watcher::RecommendedWatcher(recommended_watcher);
watcher.add_paths(config_paths)?;
Ok((watcher, receiver))
}
WatcherConfig::PollWatcher(interval) => {
let config =
notify::Config::default().with_poll_interval(Duration::from_secs(*interval));
let poll_watcher = notify::PollWatcher::new(sender, config)?;
let mut watcher = Watcher::PollWatcher(poll_watcher);
watcher.add_paths(config_paths)?;
Ok((watcher, receiver))
}
let watcher = match watcher_conf {
WatcherConfig::RecommendedWatcher => {
let recommended_watcher = recommended_watcher(sender)?;
Watcher::RecommendedWatcher(recommended_watcher)
}
WatcherConfig::PollWatcher(interval) => {
let config =
notify::Config::default().with_poll_interval(Duration::from_secs(*interval));
let poll_watcher = notify::PollWatcher::new(sender, config)?;
Watcher::PollWatcher(poll_watcher)
};
watcher.add_paths(config_paths)?;
Ok((watcher, receiver))

Copy link
Author

Choose a reason for hiding this comment

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

yeah, this seems elegant. i'll do that

env = "VECTOR_WATCH_CONFIG_POLL_INTERVAL_SECONDS",
default_value = "30"
)]
pub watch_config_poll_interval_seconds: NonZeroU64,
Copy link
Contributor

Choose a reason for hiding this comment

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

I think we should update this documentation to explain the polling watcher and when to use it

https://vector.dev/docs/administration/management/#automatic-reloading-on-configuration-change

But first lets see what maintainers think about documenting this

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.

Polling based extension of the —watch-config flag that doesn’t rely on inotify/SIGHUP
4 participants