From 18a638bc3a4ff9933b281b3bf6ce14af15988fc4 Mon Sep 17 00:00:00 2001 From: curo1305 Date: Sat, 18 Apr 2026 02:25:16 +0200 Subject: [PATCH] Fix plugin list bug and switch watcher to PollingObserver - Fix: list_plugins imported _REGISTRY as a direct reference to the empty list that existed at import time; register_services() replaces _REGISTRY with a new list so the imported reference was always []. Added get_registry() helper so callers access the live list via the module namespace. GET /api/plugins now correctly returns accessible plugins for the current user. - Fix: switch watchdog from InotifyObserver to PollingObserver. Inotify events from the macOS host are not forwarded through the Docker bind mount, so new files were only detected via the startup scan. PollingObserver (1s default interval) works reliably on all platforms including macOS+Docker bind mounts. Co-Authored-By: Claude Sonnet 4.6 --- backend/app/routers/plugins.py | 4 ++-- backend/app/services/service_health.py | 5 +++++ features/doc-service/app/services/file_watcher.py | 4 ++-- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/backend/app/routers/plugins.py b/backend/app/routers/plugins.py index e9ed573..e547adc 100644 --- a/backend/app/routers/plugins.py +++ b/backend/app/routers/plugins.py @@ -20,7 +20,7 @@ from sqlalchemy.ext.asyncio import AsyncSession from app.database import get_db from app.deps import check_plugin_access, get_current_user from app.models.user import User -from app.services.service_health import _REGISTRY, get_cached_manifest, get_service_url +from app.services.service_health import get_cached_manifest, get_registry, get_service_url router = APIRouter() @@ -72,7 +72,7 @@ async def list_plugins( ) -> list[dict]: """Return the list of plugins the current user may access.""" accessible = [] - for svc in _REGISTRY: + for svc in get_registry(): manifest = get_cached_manifest(svc.id) if manifest is None: continue diff --git a/backend/app/services/service_health.py b/backend/app/services/service_health.py index 44d0062..0805075 100644 --- a/backend/app/services/service_health.py +++ b/backend/app/services/service_health.py @@ -162,3 +162,8 @@ def get_service_url(service_id: str) -> str | None: if svc.id == service_id: return svc.internal_url return None + + +def get_registry() -> list[ServiceDefinition]: + """Return the current service registry (always up-to-date after register_services).""" + return _REGISTRY diff --git a/features/doc-service/app/services/file_watcher.py b/features/doc-service/app/services/file_watcher.py index e0bdde0..e9de9d7 100644 --- a/features/doc-service/app/services/file_watcher.py +++ b/features/doc-service/app/services/file_watcher.py @@ -25,7 +25,7 @@ import uuid from pathlib import Path from watchdog.events import FileSystemEventHandler -from watchdog.observers import Observer +from watchdog.observers.polling import PollingObserver from app.database import AsyncSessionLocal from app.models.category import DocumentCategory @@ -226,7 +226,7 @@ class FileWatcherService: return handler = _PdfEventHandler(self._watch_root, self._loop, config) - self._observer = Observer() + self._observer = PollingObserver() self._observer.schedule(handler, watch_path, recursive=True) self._observer.start() logger.info("[watcher] started, watching %s", watch_path)