From ea4118ffcdff9ab6c25d777b6215eeb8815b42b6 Mon Sep 17 00:00:00 2001 From: perco Date: Wed, 3 Jun 2026 14:59:18 +0200 Subject: [PATCH] Fix silent watcher thread death with watchdog supervisor Move time.sleep inside the try/except to catch BaseException-level failures, and wrap the watcher thread in a supervisor that auto-restarts it within 5s if it ever exits unexpectedly. Co-Authored-By: Claude Sonnet 4.6 --- app/main.py | 13 +++++++++++-- app/watcher.py | 3 ++- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/app/main.py b/app/main.py index 1edd0b4..0f46e00 100644 --- a/app/main.py +++ b/app/main.py @@ -26,11 +26,20 @@ os.makedirs(os.path.join(ANNOTATIONS_DIR, "images"), exist_ok=True) os.makedirs(os.path.join(ANNOTATIONS_DIR, "labels"), exist_ok=True) +def _watcher_supervisor(): + while True: + t = threading.Thread(target=watcher.run_watcher, daemon=True, name="watcher") + t.start() + t.join() + logging.warning("Watcher thread exited unexpectedly — restarting in 5s") + time.sleep(5) + + @asynccontextmanager async def lifespan(app: FastAPI): database.init_db() - t = threading.Thread(target=watcher.run_watcher, daemon=True) - t.start() + sup = threading.Thread(target=_watcher_supervisor, daemon=True, name="watcher-supervisor") + sup.start() yield diff --git a/app/watcher.py b/app/watcher.py index 2bfda44..7a4f3ff 100644 --- a/app/watcher.py +++ b/app/watcher.py @@ -377,6 +377,7 @@ def run_watcher(): _last_event_time = now log.info("Vehicle detected!") _process_event() + time.sleep(POLL_INTERVAL) except Exception as e: log.error(f"Watcher loop error: {e}", exc_info=True) - time.sleep(POLL_INTERVAL) + time.sleep(POLL_INTERVAL)