はじめに
こちらの案件で永続的にファイルの変更を監視し、変更があった場合にS3のファイルを更新するというシステムを構築することになりました。
djangoと組み合わせることができそうなwatchdogを採用することにしました。
djangoのコマンドにwatchdogの処理を書き、
ファイルの変更検知した際にdjango内にあるAPIを使って処理を書きました。
watchdogで永続的に処理を実行する為にsupervisordを使っています。
※この記事ではdjangoの設定は割愛します。
djangoのコマンドの記述例
project/management/commands
import argparse from django.core.management.base import BaseCommand from watchdog.events import FileSystemEventHandler from watchdog.observers import Observer import os import time from ...views import IndexViews ←viewに処理を渡します import logging import requests import json import glob import datetime env = environ.Env() env.read_env('.env') logger = logging.getLogger(__name__) class Command(BaseCommand): help = 'これはテスト用のコマンドバッチです' def add_arguments(self, parser): parser.add_argument('request', nargs='+', type=str) def handle(self, *args, **options): # 起動ログ print('フォルダ・ファイル監視スクリプトを起動します。') logger.info('フォルダ・ファイル監視スクリプトを起動します。') # 現在のフォルダパスを取得する(プログラムが実行されているフォルダパス) current_directory = os.path.dirname(os.path.abspath(__file__)) print(current_directory) # インスタンス作成 event_handler = ChangeHandler() observer = Observer() # 監視の開始 observer.start() try: # 無限ループ while True: # 待機 time.sleep(0.05) except KeyboardInterrupt: # 監視の終了 observer.stop() # スレッド停止を待つ observer.join() # 終了ログ print('フォルダ・ファイル監視スクリプトを終了します。') logger.info('フォルダ・ファイル監視スクリプトを終了します。') class ChangeHandler(FileSystemEventHandler): # ファイルやフォルダが作成された場合 def on_created(self, event): filepath = event.src_path filename = os.path.basename(filepath) request = [filepath.replace('~', ''), filename.replace('~', '')] try: response = IndexViews.createFile(request) except Exception as e: logger.info(e) logger.info('create FAILURE' + filepath) logger.info('create SUCCESS' + filepath) # ファイルやフォルダが更新された場合 def on_modified(self, event): filepath = event.src_path filename = os.path.basename(filepath) logger.info('update START' + filepath) try: request = [filepath.replace('~', ''), filename.replace('~', '')] response = IndexViews.updateFile(request) except Exception as e: logger.info(e) logger.info('update FAILURE' + filepath) logger.info('update SUCCESS' + filepath) # ファイルやフォルダが移動された場合 def on_moved(self, event): # 移動された場合に呼ばれる今回は使っていない # ファイルやフォルダが削除された場合 def on_deleted(self, event): filepath = event.src_path filename = os.path.basename(filepath) request = [filepath.replace('~', ''), filename.replace('~', '')] try: response = IndexViews.deleteFile(request) except Exception as e: logger.info(e) logger.info('delete FAILURE' + filepath) logger.info('delete SUCCESS' + filepath)
ファイルの変更を検知した場合にファイルパスとファイル名を受け取ってViewに流しています。
supervisorの設定例
まずはsupervisorをインストール
pip install supervisor
設定ファイルを書き出す
echo_supervisord_conf > /etc/supervisord.conf
設定ファイル内のコメントファイルを外しiniファイルを読むようにする
vim /etc/supervisord.conf コメントアウトを外す [include] files = /etc/supervisord.d/*.ini
iniファイルを作成
touch /etc/supervisord.d/django-worker.ini
以下をiniファイルに記述
[program:django-worker-sample] process_name=%(program_name)s_%(process_num)02d command=python manage.py {コマンド名} autostart=true autorestart=true user=root numprocs=1 directory={アプリのパス} redirect_stderr=true stdout_logfile=/var/log/supervisor/myprog.log stderr_logfile=/var/log/supervisor/myprog-error.log
supervisordを起動
systemctl enable supervisord systemctl start supervisord
監視しているパスでファイルを作成し、動いているか確認
まとめ
この技術を使った事例がこちら:
https://www.iret.co.jp/works/106.html