notify-rs / notify

🔭 Cross-platform filesystem notification library for Rust.
https://docs.rs/notify
2.59k stars 206 forks source link

On linux, wrong message while watching a single file and update it #394

Open lulujun2233 opened 2 years ago

lulujun2233 commented 2 years ago

System details

What you did (as detailed as you can)

1:I watched a single file:/root/test/6 watch_items [WatchItem path: "/root/test/6", r true, f true] [file_system/src/file_watcher/watcher.rs 218] 2:I modify it via vim

What you expected

Receive Modify event

What happened

I received events as below include Remove event,and then, I could not receive any events of this file even if I watched it again (not restart the program)

eventEvent { kind: Modify(Name(From)), paths: ["/root/test/6"], attr:tracker: None, attr:flag: None, attr:info: None, attr:source: None } eventEvent { kind: Modify(Metadata(Any)), paths: ["/root/test/6"], attr:tracker: None, attr:flag: None, attr:info: None, attr:source: None } eventEvent { kind: Remove(File), paths: ["/root/test/6"], attr:tracker: None, attr:flag: None, attr:info: None, attr:source: None }

mdean75 commented 2 years ago

There is a combination of inotify and vim at play here. I'm new to Rust, but have experienced this same behavior with the Go fsnotify package. By verbosely logging all events received, I was able to see that when a file is edited in vim that there swap files that get created and ultimately the inode of the file (which is the actual thing being watched) ends up getting changed. See this stack exchange answer for more detail https://unix.stackexchange.com/questions/36467/why-inode-value-changes-when-we-edit-in-vi-editor. Also keep in mind that frequently vi is aliased to vim based on my experience (i'm not sure if that's distro specific or from sys admins) so that can change how you approach the problem as outlined in the linked stack exchange answer.

This appears to be limited to linux as I have tested this case on os x using notify-rs. I watched a specific file, edited it with vi, edited it with vim, even deleted and recreated the file and after all events still received notify events for the file. I can't confirm anything with Windows, but this appears to be how the inotify vs fsevents api works in combination with vi/vim. It is opinion, at least for something that needs to run reliably on linux, that the best practice is to watch a directory instead of specific files and when an event is triggered compare the file name that triggered the event to a list of files you want to watch.

0xpr03 commented 2 years ago

See also #247 Watching the whole directory is definitely recommended. Files do not behave consistently as you'd expect them to..

honglei commented 11 months ago

Watch a conf file is very common, hope support it. https://github.com/samuelcolvin/watchfiles/issues/235 Rigth now I use the following way to keep watching the config file at runtime.

from typing import Callable
import os
import pathlib
import logging
import traceback
import asyncio
from watchfiles import awatch
async def watch_file_change(
    configFilePath: pathlib.Path,
    func: Callable
    ):
    """
    监视配置文件变更
    """
    assert configFilePath is not None
    while True:
        try:
            assert os.path.isfile(configFilePath)
            async for changes in awatch(configFilePath):
                logging.warning(f"conf changed! {changes}")
                func()
                break 
        except Exception as e:
            logging.error(traceback.format_exc())
            logging.warning(f"{configFilePath=}")
            await asyncio.sleep(120)
honglei commented 11 months ago

There are many processes, each process only watch their only config file rather than a dir ,because the dir has many config files.

|---config_for_proc_1 |---config_for_proc_2 |---..