watchdog.observers.Observer 适用于 Windows,适用于 docker Linux,不适用于 docker Windows
watchdog.observers.Observer works in Windows, works in docker on Linux, does not work in docker on Windows
我有一个有趣的问题让我抓狂。我有一个 python 程序正在使用 watchdog.observers.Observer。该程序(又名 watcher)监视文件夹并在其中出现文件时做出响应。我有另一个程序(又名解析器),它会定期用文件填充监视的文件夹。
- 当 Windows 中的观察程序 运行 和 Windows 上的 docker 容器中的解析器 运行 时,就会有幸福。
- 当观察程序 运行s 在 Linux 框的 docker 容器中,解析器 运行s 在另一个 docker 容器中Linux盒子里,有幸福。
- 当观察程序 运行s 在 Windows 的 docker 容器中,解析器 运行s 在 Windows 的另一个 docker 容器中=],幸福没有实现。解析器用文件填充文件夹,但观察者从不观察它们。
这是我的观察者代码:
import os
import sys
import time
from watchdog.observers import Observer
from event_handler import ImagesEventHandler
from constants import ROOT_FOLDER, IMAGES_FOLDER, CWD
class ImagesWatcher:
def __init__(self, src_path):
self.__src_path = src_path
print(self.__src_path)
self.__event_handler = ImagesEventHandler()
self.__event_observer = Observer()
print("********** Inside ImagesWatcher --init__ method just after instantiating ImagesEventHandler and Observer **************")
def run(self):
print("********** Inside ImagesWatcher run method **************")
self.start()
try:
while True:
time.sleep(1)
except KeyboardInterrupt:
self.stop()
def start(self):
print("********** Inside ImagesWatcher start method **************")
self.__schedule()
self.__event_observer.start()
def stop(self):
print("********** Inside ImagesWatcher stop method **************")
self.__event_observer.stop()
self.__event_observer.join()
def __schedule(self):
print("********** Inside ImagesWatcher __schedule method **************")
print(self.__src_path)
self.__event_observer.schedule(
self.__event_handler,
self.__src_path,
recursive=True
)
if __name__ == "__main__":
src_path = sys.argv[1] if len(sys.argv) > 1 else CWD
src_path = os.path.abspath(src_path)
watch_path = os.path.join(src_path, ROOT_FOLDER)
watch_path = os.path.join(watch_path, IMAGES_FOLDER)
print('watch_path: ' + watch_path)
if not os.path.exists(watch_path):
os.makedirs(watch_path)
print('just created: ' + watch_path)
ImagesWatcher(watch_path).run()
这是关联的事件处理程序代码:
import os
from PIL import Image
from watchdog.events import FileSystemEventHandler
from lambda_function import lambda_handler
from time import sleep
from os.path import dirname, abspath
class ImagesEventHandler(FileSystemEventHandler):
def __init__(self,):
print("********** Inside event handler __init__ method **************")
def on_created(self, event):
print("********** Inside event handler on_created method **************")
self.process(event)
def process(self, event):
print("********** Inside event handler process method **************")
sleep(2)
image = Image.open(event.src_path)
tracking_dir=os.path.join(dirname(dirname(abspath(event.src_path))),'Tracking')
print("******************** tracking_dir: ' + tracking_dir + ' ********************")
lambda_handler(image,tracking_dir)
永远不会执行观察者的停止方法。事件处理程序的init方法被执行,但是on_created和process方法都没有被执行。
这是我构建和 运行 docker 容器的方式:
docker build -t watcher -f docker/watcher/Dockerfile .
docker run -d --network onprem_network -v c:\My_MR:/code/My_MR --name watcher watcher
docker build -t parser -f docker/parser/Dockerfile .
docker run -d --network onprem_network -v c:\My_MR:/code/My_MR --name parser parser
我的观察者 Dockerfile:
FROM python:3.7.9
ENV PYTHONUNBUFFERED 1
ENV PYTHONDONTWRITEBYTECODE 1
COPY requirements.txt /requirements.txt
RUN pip install --upgrade pip -r /requirements.txt && mkdir /code
WORKDIR /code
COPY . /code/
RUN apt update && apt-get update && apt install tesseract-ocr -y && apt-get install ffmpeg libsm6 libxext6 -y
CMD ["python", "/code/watcher.py"]
我的解析器 Dockerfile:
FROM python:3.7.9
ENV PYTHONUNBUFFERED 1
ENV PYTHONDONTWRITEBYTECODE 1
COPY requirements.txt /requirements.txt
RUN pip install --upgrade pip -r /requirements.txt && mkdir /code
WORKDIR /code
COPY . /code/
RUN apt update && apt-get update && apt-get install ffmpeg -y
CMD ["python", "/code/parser.py"]
我的requirements.txt:
Pillow == 5.4.1
gql == 3.0.0a5
matplotlib == 3.0.3
numpy == 1.16.2
opencv_python == 4.4.0.44
pandas == 0.24.2
pytesseract == 0.2.6
python_ffmpeg_video_streaming == 0.1.14
watchdog == 2.0.2
requests
tesseract
如有任何帮助,我们将不胜感激。
watchdog 用来监视 linux 文件系统事件的底层 API 称为 inotify。 Docker for Windows WSL 2 backend documentation 注释:
Linux containers only receive file change events (“inotify events”) if the original files are stored in the Linux filesystem.
您正在挂载的目录 c:\My_MR
驻留在 Windows 文件系统上,因此观察器容器内的 inotify 不起作用。
相反,您可以 运行 docker 从 在您的 WSL 2 默认分发 中使用 linux 文件系统路径,例如 ~/my_mr
:
docker run -d --network onprem_network -v ~/my_mr:/code/My_MR --name watcher watcher
docker run -d --network onprem_network -v ~/my_mr:/code/My_MR --name parser parser
可以从 Windows 访问此目录,而 WSL 2 分发 运行ning 使用 \wsl$\
网络路径,即 \wsl$\<Distro name>\home\<username>\my_mr
(更多信息 here).因此,我相信 docker run
也可以从 Windows 使用 \wsl$\
路径和 -v
.
Docker Windows 音量观察器
也可以使用Docker Windows Volume Watcher。
Python 脚本监视托管在 Windows 上的 Docker 容器的文件夹绑定,并使用文件更改更新这些容器。
使用 pip
安装(支持 Python 2 和 3)。
pip install docker-windows-volume-watcher
监控所有容器的所有目录绑定。
docker-volume-watcher
仅监控容器 container_name 的绑定。
docker-volume-watcher container_name
仅监控 container_name 到主机目录 C:\some\directory.
的绑定
docker-volume-watcher container_name C:\some\directory
限制
- 脚本不会传播到容器文件删除事件。
- 该脚本需要在容器中安装 stat 和 chmod 实用程序。
https://forums.docker.com/t/file-system-watch-does-not-work-with-mounted-volumes/12038/9
http://blog.subjectify.us/miscellaneous/2017/04/24/docker-for-windows-watch-bindings.html
看门狗和 PollingObserver()
另一个解决方案是使用class PollingObserver
。
但是如果 watchdog 必须用一个时间表监视多个文件和文件夹,它会显着变慢。
import sys
import time
import logging
from watchdog.observers.polling import PollingObserver
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 = PollingObserver()
# Limit the number of files by setup multiple schedule
observer.schedule(event_handler, '/folder/subfolder') # All files in a subfolder
observer.schedule(event_handler, '/folder/file') # A file
observer.schedule(event_handler, '/folder/file2') # A file
# etc...
observer.start()
try:
while True:
time.sleep(1)
except KeyboardInterrupt:
observer.stop()
observer.join()
我有一个有趣的问题让我抓狂。我有一个 python 程序正在使用 watchdog.observers.Observer。该程序(又名 watcher)监视文件夹并在其中出现文件时做出响应。我有另一个程序(又名解析器),它会定期用文件填充监视的文件夹。
- 当 Windows 中的观察程序 运行 和 Windows 上的 docker 容器中的解析器 运行 时,就会有幸福。
- 当观察程序 运行s 在 Linux 框的 docker 容器中,解析器 运行s 在另一个 docker 容器中Linux盒子里,有幸福。
- 当观察程序 运行s 在 Windows 的 docker 容器中,解析器 运行s 在 Windows 的另一个 docker 容器中=],幸福没有实现。解析器用文件填充文件夹,但观察者从不观察它们。
这是我的观察者代码:
import os
import sys
import time
from watchdog.observers import Observer
from event_handler import ImagesEventHandler
from constants import ROOT_FOLDER, IMAGES_FOLDER, CWD
class ImagesWatcher:
def __init__(self, src_path):
self.__src_path = src_path
print(self.__src_path)
self.__event_handler = ImagesEventHandler()
self.__event_observer = Observer()
print("********** Inside ImagesWatcher --init__ method just after instantiating ImagesEventHandler and Observer **************")
def run(self):
print("********** Inside ImagesWatcher run method **************")
self.start()
try:
while True:
time.sleep(1)
except KeyboardInterrupt:
self.stop()
def start(self):
print("********** Inside ImagesWatcher start method **************")
self.__schedule()
self.__event_observer.start()
def stop(self):
print("********** Inside ImagesWatcher stop method **************")
self.__event_observer.stop()
self.__event_observer.join()
def __schedule(self):
print("********** Inside ImagesWatcher __schedule method **************")
print(self.__src_path)
self.__event_observer.schedule(
self.__event_handler,
self.__src_path,
recursive=True
)
if __name__ == "__main__":
src_path = sys.argv[1] if len(sys.argv) > 1 else CWD
src_path = os.path.abspath(src_path)
watch_path = os.path.join(src_path, ROOT_FOLDER)
watch_path = os.path.join(watch_path, IMAGES_FOLDER)
print('watch_path: ' + watch_path)
if not os.path.exists(watch_path):
os.makedirs(watch_path)
print('just created: ' + watch_path)
ImagesWatcher(watch_path).run()
这是关联的事件处理程序代码:
import os
from PIL import Image
from watchdog.events import FileSystemEventHandler
from lambda_function import lambda_handler
from time import sleep
from os.path import dirname, abspath
class ImagesEventHandler(FileSystemEventHandler):
def __init__(self,):
print("********** Inside event handler __init__ method **************")
def on_created(self, event):
print("********** Inside event handler on_created method **************")
self.process(event)
def process(self, event):
print("********** Inside event handler process method **************")
sleep(2)
image = Image.open(event.src_path)
tracking_dir=os.path.join(dirname(dirname(abspath(event.src_path))),'Tracking')
print("******************** tracking_dir: ' + tracking_dir + ' ********************")
lambda_handler(image,tracking_dir)
永远不会执行观察者的停止方法。事件处理程序的init方法被执行,但是on_created和process方法都没有被执行。
这是我构建和 运行 docker 容器的方式:
docker build -t watcher -f docker/watcher/Dockerfile .
docker run -d --network onprem_network -v c:\My_MR:/code/My_MR --name watcher watcher
docker build -t parser -f docker/parser/Dockerfile .
docker run -d --network onprem_network -v c:\My_MR:/code/My_MR --name parser parser
我的观察者 Dockerfile:
FROM python:3.7.9
ENV PYTHONUNBUFFERED 1
ENV PYTHONDONTWRITEBYTECODE 1
COPY requirements.txt /requirements.txt
RUN pip install --upgrade pip -r /requirements.txt && mkdir /code
WORKDIR /code
COPY . /code/
RUN apt update && apt-get update && apt install tesseract-ocr -y && apt-get install ffmpeg libsm6 libxext6 -y
CMD ["python", "/code/watcher.py"]
我的解析器 Dockerfile:
FROM python:3.7.9
ENV PYTHONUNBUFFERED 1
ENV PYTHONDONTWRITEBYTECODE 1
COPY requirements.txt /requirements.txt
RUN pip install --upgrade pip -r /requirements.txt && mkdir /code
WORKDIR /code
COPY . /code/
RUN apt update && apt-get update && apt-get install ffmpeg -y
CMD ["python", "/code/parser.py"]
我的requirements.txt:
Pillow == 5.4.1
gql == 3.0.0a5
matplotlib == 3.0.3
numpy == 1.16.2
opencv_python == 4.4.0.44
pandas == 0.24.2
pytesseract == 0.2.6
python_ffmpeg_video_streaming == 0.1.14
watchdog == 2.0.2
requests
tesseract
如有任何帮助,我们将不胜感激。
watchdog 用来监视 linux 文件系统事件的底层 API 称为 inotify。 Docker for Windows WSL 2 backend documentation 注释:
Linux containers only receive file change events (“inotify events”) if the original files are stored in the Linux filesystem.
您正在挂载的目录 c:\My_MR
驻留在 Windows 文件系统上,因此观察器容器内的 inotify 不起作用。
相反,您可以 运行 docker 从 在您的 WSL 2 默认分发 中使用 linux 文件系统路径,例如 ~/my_mr
:
docker run -d --network onprem_network -v ~/my_mr:/code/My_MR --name watcher watcher
docker run -d --network onprem_network -v ~/my_mr:/code/My_MR --name parser parser
可以从 Windows 访问此目录,而 WSL 2 分发 运行ning 使用 \wsl$\
网络路径,即 \wsl$\<Distro name>\home\<username>\my_mr
(更多信息 here).因此,我相信 docker run
也可以从 Windows 使用 \wsl$\
路径和 -v
.
Docker Windows 音量观察器
也可以使用Docker Windows Volume Watcher。 Python 脚本监视托管在 Windows 上的 Docker 容器的文件夹绑定,并使用文件更改更新这些容器。
使用 pip
安装(支持 Python 2 和 3)。
pip install docker-windows-volume-watcher
监控所有容器的所有目录绑定。
docker-volume-watcher
仅监控容器 container_name 的绑定。
docker-volume-watcher container_name
仅监控 container_name 到主机目录 C:\some\directory.
的绑定docker-volume-watcher container_name C:\some\directory
限制
- 脚本不会传播到容器文件删除事件。
- 该脚本需要在容器中安装 stat 和 chmod 实用程序。
https://forums.docker.com/t/file-system-watch-does-not-work-with-mounted-volumes/12038/9 http://blog.subjectify.us/miscellaneous/2017/04/24/docker-for-windows-watch-bindings.html
看门狗和 PollingObserver()
另一个解决方案是使用class PollingObserver
。
但是如果 watchdog 必须用一个时间表监视多个文件和文件夹,它会显着变慢。
import sys
import time
import logging
from watchdog.observers.polling import PollingObserver
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 = PollingObserver()
# Limit the number of files by setup multiple schedule
observer.schedule(event_handler, '/folder/subfolder') # All files in a subfolder
observer.schedule(event_handler, '/folder/file') # A file
observer.schedule(event_handler, '/folder/file2') # A file
# etc...
observer.start()
try:
while True:
time.sleep(1)
except KeyboardInterrupt:
observer.stop()
observer.join()