diff --git a/app/core/celery_config.py b/app/core/celery_config.py index 58214124..e71e72a6 100644 --- a/app/core/celery_config.py +++ b/app/core/celery_config.py @@ -64,6 +64,44 @@ def get_all_task_modules() -> list[str]: return [] +def _preload_all_module_models() -> None: + """ + Import every module's models package up front. + + The Celery worker process loads task modules but not routes/services, + so models reached only via SQLAlchemy string-based relationships + (e.g. Platform -> "ContentPage") never get imported. The first DB + query then explodes with InvalidRequestError when the mapper tries + to resolve the unknown name. The FastAPI process avoids this because + api_router transitively imports everything; we replicate that effect + here for the worker. + """ + import importlib + + try: + from app.modules.registry import MODULES + except ImportError as e: + logger.warning(f"Could not load module registry for model preload: {e}") + return + + loaded = 0 + for code in MODULES: + module_path = f"app.modules.{code}.models" + try: + importlib.import_module(module_path) + loaded += 1 + except ModuleNotFoundError: + # Module doesn't expose a models package — fine, skip. + continue + except Exception as e: + logger.warning(f"Failed preloading {module_path}: {e}") + + logger.info(f"Preloaded models for {loaded} modules (SQLAlchemy mapper resolution)") + + +_preload_all_module_models() + + # Create Celery application celery_app = Celery( "orion",