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

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

Open
lulujun2233 opened this issue Mar 16, 2022 · 4 comments
Open
Labels
B-unconfirmed Needs verification (by maintainer or testing party) os-linux

Comments

@lulujun2233
Copy link

lulujun2233 commented Mar 16, 2022

System details

  • OS/Platform name and version: Ubuntu 20.04.3 LTS

  • Rust version (if building from source): rustc --version: 1.58.1

  • Notify version (or commit hash if building from git): 5.0.0-pre.13

  • On Linux: Kernel version:Linux version 5.4.0-84-generic

  • If you're running as a privileged user (root, System):root

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 }

@lulujun2233 lulujun2233 changed the title On linux, wrong message while watch a single file and update it On linux, wrong message while watching a single file and update it Mar 16, 2022
@mdean75
Copy link

mdean75 commented Apr 1, 2022

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
Copy link
Member

0xpr03 commented Apr 1, 2022

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

@honglei
Copy link

honglei commented Aug 18, 2023

Watch a conf file is very common, hope support it. samuelcolvin/watchfiles#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
Copy link

honglei commented Aug 18, 2023

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
|---..

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
B-unconfirmed Needs verification (by maintainer or testing party) os-linux
Projects
None yet
Development

No branches or pull requests

4 participants