From 45610c9ea00935114e300c4d7b30e482d41ec1f3 Mon Sep 17 00:00:00 2001 From: KWON Date: Mon, 28 Jul 2025 17:12:28 +0900 Subject: [PATCH] =?UTF-8?q?=ED=8C=8C=EC=9D=BC=20=EA=B0=90=EC=8B=9C=20?= =?UTF-8?q?=EA=B8=B0=EB=8A=A5=20=EA=B0=95=ED=99=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/file_watch.py | 68 +++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 57 insertions(+), 11 deletions(-) diff --git a/lib/file_watch.py b/lib/file_watch.py index 4fc7ba6..a6fc358 100644 --- a/lib/file_watch.py +++ b/lib/file_watch.py @@ -1,6 +1,7 @@ import time import os from watchdog.observers import Observer +from watchdog.observers.polling import PollingObserver # 필요시 사용 from watchdog.events import FileSystemEventHandler import threading @@ -20,27 +21,40 @@ class NewFileHandler(FileSystemEventHandler): self._processing_files = set() def on_created(self, event): + self._handle_event(event) + + def on_moved(self, event): + # moved event는 dest_path 사용 + self._handle_event(event, moved=True) + + def on_modified(self, event): + self._handle_event(event) + + def _handle_event(self, event, moved=False): if event.is_directory: return - filepath = event.src_path + + filepath = event.dest_path if moved else event.src_path filename = os.path.basename(filepath) + if not filename.endswith(FILE_EXTENSIONS): return - # 처리 대상 여부 확인 if filename.startswith(BILL_PREFIX) or filename.startswith(DAILY_PRODUCT_PREFIX): - print(f"[WATCHER] 신규 파일 감지: {filename}") + with self._lock: + if filename in self._processing_files: + print(f"[WATCHER] {filename} 이미 처리 중") + return + self._processing_files.add(filename) + threading.Thread(target=self.process_file, args=(filepath, filename), daemon=True).start() def process_file(self, filepath, filename): - with self._lock: - if filename in self._processing_files: - print(f"[WATCHER] {filename} 이미 처리 중") - return - self._processing_files.add(filename) - try: - time.sleep(3) # 파일 쓰기 완료 대기 + # 파일 완전 생성/복사 대기 (파일 크기 변화 없을 때까지 기다림) + if not self.wait_for_file_stable(filepath): + print(f"[WATCHER] 파일 안정화 실패, 처리 중단: {filename}") + return print(f"[WATCHER] 파일 처리 시작: {filename}") if filename.startswith(BILL_PREFIX): @@ -63,10 +77,42 @@ class NewFileHandler(FileSystemEventHandler): with self._lock: self._processing_files.discard(filename) + def wait_for_file_stable(self, filepath, wait_seconds=10, interval=1): + """ + 파일 크기가 interval 간격으로 변하지 않으면 안정화된 것으로 판단 + """ + last_size = -1 + stable_count = 0 + required_stable_count = int(wait_seconds / interval) + + for _ in range(required_stable_count): + try: + current_size = os.path.getsize(filepath) + except FileNotFoundError: + # 파일이 없어지면 중단 + return False + + if current_size == last_size: + stable_count += 1 + if stable_count >= required_stable_count: + return True + else: + stable_count = 0 + last_size = current_size + + time.sleep(interval) + + return False + def start_watching(): print(f"[WATCHER] '{DATA_DIR}' 폴더 감시 시작") + event_handler = NewFileHandler() - observer = Observer() + + # 기본 Observer 대신 PollingObserver로 변경 가능 (Docker 환경에서 안정적) + #observer = Observer() + observer = PollingObserver() # 필요시 이걸로 바꿔서 사용 + observer.schedule(event_handler, DATA_DIR, recursive=False) observer.start() try: