LoginSignup
3
5

More than 1 year has passed since last update.

Pythonのフォルダ監視(Watchdog)は例外で停止する

Last updated at Posted at 2023-01-28

Pythonのフォルダ監視(Watchdog)は例外で停止する

環境

  • Python 3.11
  • Watchdog 2.1.9

要約

PythonのWatchdogパッケージでフォルダ監視を行う時に、予期せぬエラーによる監視終了を避けるには、フォルダイベントに対する処理を別スレッドで行えばよい。

現象

Pythonでフォルダ監視というと、標準ライブラリではカバーしておらずWatchdogを使う方法がメジャーだと思われる。フォルダ監視をプログラム実行中永続的に行わせるケースは多いと思われるが、Watchdogから呼び出した命令で予期せぬ例外が発生した場合、フォルダ監視は終了してしまう。

さっと検索した限り、これを問題として取り上げている記事は見つからなかった。

サンプルコード

#!/usr/bin/python3
"""例示用."""

import threading
from pathlib import Path
from typing import NoReturn

from watchdog.events import FileSystemEventHandler
from watchdog.observers import Observer


class TestHandler(FileSystemEventHandler):
    """フォルダ内でファイルが作成されたときの処理を規定するクラス."""

    def irregular(self) -> NoReturn:
        """例外を発生させる."""
        raise Exception("Exception in on_created.")

    def on_created(self, event) -> None:
        """ファイル生成もしくはファイルが移動してきた時の対応."""
        print(f"created: {event.src_path=}")
        self.irregular()
        # threading.Thread(target=self.irregular).start()


if __name__ == '__main__':
    TEST_PATH = "test"
    Path(TEST_PATH).mkdir(parents=True, exist_ok=True)

    observer = Observer()
    observer.schedule(TestHandler(), TEST_PATH, recursive=True)
    observer.start()
    try:
        while observer.is_alive():
            observer.join(1)
    finally:
        observer.stop()
        observer.join()

TEST_PATH内にファイルを作成すると、例外が発生してプログラムが終了する。当然、もう一つファイルを作成しても何も起こらない。

対策

サンプルコード内にコメントアウトしてあるが、self.irregular()threading.Thread(target=self.irregular).start()と変更して別スレッドで実行すれば、少なくともフォルダ監視が止まることはなくなる。

考察

例外が発生した時に、エラーに気づけるようにプログラムが停止した方がいいのか、エラーを抱えたまま動作を続けた方がいいのかについては議論が分かれることもあると思うが、永続的フォルダ監視の場合、個々のイベントへの対応が独立していて動作の継続の方が重要であるケースは多いのではと思う。

事前にエラーを網羅するのは困難であることを考えれば、動作継続が優先する時にFileSystemEventHandlerから呼び出す処理を予め別スレッドでの実行となるように書いておくのは方法論として有効だと言える。

エラーの発見は、TestHandler.irregular()内の処理をtry ... exceptで囲ってログを取るなどの方法で対処できると思われる。

余談

余談だが、上記は2023/1/28時点のWatchdog公式QuickStartのサンプルコードを参考に作成したが、while observer.is_alive():while observer.isAlive():になっていたため動作せず、ちょっと戸惑った。

ちなみにGitHubのサンプルコードのようにwhile True:でループすると、プログラムは終了していないのにフォルダ監視だけ終了しているという、大変エラーがわかりにくい状態になる。

改訂履歴(表現の修正などは除く)

  • 2023/1/28: 初版
3
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
5