watchdog.observers.Observer 在 Windows 中工作,在 Linux 上的 docker 中工作,在 Windows 上的 docker 中不起作用

Phi*_*l O 5 python watchdog docker

我有一个有趣的问题让我发疯。我有一个使用 watchdog.observers.Observer 的 python 程序。该程序(又名观察程序)监视文件夹并在文件出现在其中时做出响应。我有另一个程序(又名解析器),它定期用文件填充监视的文件夹。

  1. 当观察程序在Windows中运行并且解析器在Windows上的docker容器中运行时,就会有幸福。
  2. 当观察程序在 Linux 机器上的 docker 容器中运行并且解析器在 Linux 机器上的另一个 docker 容器中运行时,就会感到幸福。
  3. 当观察者程序运行在 Windows 上的一个 docker 容器中,而解析器运行在 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()
Run Code Online (Sandbox Code Playgroud)

这是关联的事件处理程序代码:

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)
Run Code Online (Sandbox Code Playgroud)

观察者的 stop 方法永远不会被执行。执行事件处理程序的 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 
Run Code Online (Sandbox Code Playgroud)

我的观察者 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"]
Run Code Online (Sandbox Code Playgroud)

我的解析器 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"]
Run Code Online (Sandbox Code Playgroud)

我的要求.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
Run Code Online (Sandbox Code Playgroud)

任何帮助将不胜感激。

Jos*_*bst 2

watchdog 用于监视 Linux 文件系统事件的底层 API 称为 inotify。Docker for Windows WSL 2 后端文档说明:

\n
\n

如果原始文件存储在 Linux 文件系统中,Linux 容器仅接收文件更改事件 (\xe2\x80\x9cinotify events\xe2\x80\x9d)。

\n
\n

您正在安装的目录c:\\My_MR驻留在 Windows 文件系统上,因此观察程序容器内的 inotify 不起作用。

\n

相反,您可以使用 Linux 文件系统路径从WSL 2 默认发行版内部~/my_mr运行 docker,例如:

\n
docker run -d --network onprem_network -v ~/my_mr:/code/My_MR --name watcher watcher \ndocker run -d --network onprem_network -v ~/my_mr:/code/My_MR --name parser parser \n
Run Code Online (Sandbox Code Playgroud)\n

\\\\wsl$\\当 WSL 2 发行版使用网络路径运行时,可以从 Windows 访问此目录\\\\wsl$\\<Distro name>\\home\\<username>\\my_mr(更多信息请参见此处)。因此,我相信也docker run可以使用.\\\\wsl$\\-v

\n