看门狗(osx)未通知远程网络更改



我正在使用Watchdog监视网络目录,非递归,以了解随着时间的推移将创建的特定文件模式。我看到的问题是,虽然在本地测试时效果非常好,但如果我从远程机器更改受监控的目录,则不会触发事件。

以下是我配置的具体细节:

  • OSX
  • 监视NFS装载上的单个目录(非递归)
  • python 2.6

使用股票示例片段可以很容易地重现我的问题示例:

import sys
import time
import logging
from watchdog.observers import Observer
from watchdog.events import LoggingEventHandler
if __name__ == "__main__":
    logging.basicConfig(level=logging.INFO,
                        format='%(asctime)s - %(message)s',
                        datefmt='%Y-%m-%d %H:%M:%S')
    event_handler = LoggingEventHandler()
    observer = Observer()
    observer.schedule(event_handler, path=sys.argv[1], recursive=False)
    observer.start()
    try:
        while True:
            time.sleep(1)
    except KeyboardInterrupt:
        observer.stop()
    observer.join()

如果在网络目录上启动此操作,然后从同一系统进行更改,则会调度事件。但是,如果您从网络上的另一台机器更改目录,则不会发送任何事件。

我是否遗漏了一些关于kqueue限制的内容(或者可能是OSX上的FSEvents,因为它说它是Watchdog首选的)?

我对这个python包很感兴趣,并打算开始将其用于其他脚本来代替文件系统轮询,但我似乎找不到任何关于为什么会出现这个问题的信息。

更新

我还测试了MacFSEvents,结果也出现了同样的问题。然后我修改了上面的测试脚本,强制尝试不同的观察者:

# does not work with remote changes
from watchdog.observers.fsevents import FSEventsObserver as Observer
# does not work with remote changes
from watchdog.observers.kqueue import KqueueObserver as Observer
# only option that works because its actually polling every second
from watchdog.observers.polling import PollingObserver as Observer

因此,至少目前,我可以使用轮询观察器,而不必修改我的代码,直到有人能够揭示我遇到的真正问题。

我很确定文件系统事件不能在NFS上工作,原因是内核正常管理文件系统事件的方式是它在内核中有一层可以触发活动-在NFS中没有通知更改的功能,你只能获得inode列表,写一些块,读一些块。。等等。它非常小。

要使文件系统事件在NFS上工作,您必须不断轮询NFS服务器。

AFP可能有一些功能,如果你有果汁,你可以安装netatalk并尝试一下。

如果你绝对需要做这样的事情,而netatalk没有这样做,那么你最好的办法就是启动并运行OSXFuse,并编写一个NFS覆盖层,它实际上只是坐在那里轮询更改。但是,您将被限制为"截断、修改、附加、删除"等。

另请参阅:在项目中使用libfuse,无需root访问权限(用于安装)?FTP装载&inotify/kqueue/FS事件

如果您希望在已安装的目录中有看门狗应使用PollingObserver而不是Observer

import time
from watchdog.observers import PollingObserver
from watchdog.events import FileSystemEventHandler
class MyHandler(FileSystemEventHandler):
    def on_any_event(self, event):
        print(event)
if __name__ == "__main__":
    event_handler = MyHandler()
    observer = PollingObserver()
    observer.schedule(event_handler, path='.', recursive=True)
    observer.start()
    try:
        while True:
            time.sleep(1)
    except KeyboardInterrupt:
        observer.stop()
    observer.join()

最新更新