import os import json import importlib from app.celery_instance import celery def init_celery(app): """ Wire up Celery to our Flask app, discover all plugin task modules and run any tasks_init hooks. """ # 1. Configure broker & result backend from Flask config celery.conf.broker_url = app.config['CELERY_BROKER_URL'] celery.conf.result_backend = app.config['CELERY_RESULT_BACKEND'] # 2. Make all tasks run inside the Flask application context TaskBase = celery.Task class ContextTask(TaskBase): def __call__(self, *args, **kwargs): with app.app_context(): return TaskBase.__call__(self, *args, **kwargs) celery.Task = ContextTask # 3. Discover all plugins by looking for plugin.json in plugins/ plugins_dir = os.path.join(app.root_path, '..', 'plugins') task_modules = [] for plugin_name in sorted(os.listdir(plugins_dir)): manifest = os.path.join(plugins_dir, plugin_name, 'plugin.json') if not os.path.isfile(manifest): continue # Load plugin metadata try: meta = json.load(open(manifest)) except Exception: app.logger.error(f"[Celery] Failed to load plugin.json for '{plugin_name}'") continue # a) Gather task modules (string or dict or list) tasks_cfg = meta.get('tasks') if isinstance(tasks_cfg, str): task_modules.append(tasks_cfg) elif isinstance(tasks_cfg, dict) and tasks_cfg.get('module'): task_modules.append(tasks_cfg['module']) elif isinstance(tasks_cfg, list): for entry in tasks_cfg: if isinstance(entry, str): task_modules.append(entry) elif isinstance(entry, dict) and entry.get('module'): task_modules.append(entry['module']) # b) Run any tasks_init hooks (e.g. to register schedules) for hook in meta.get('tasks_init', []): module_name = hook.get('module') fn_name = hook.get('callable') if not module_name or not fn_name: continue try: m = importlib.import_module(module_name) fn = getattr(m, fn_name) # pass the Celery instance so they can register schedules, etc. fn(celery) except Exception as e: app.logger.error(f"[Celery] Failed tasks_init for '{plugin_name}': {e}") # 4. Autodiscover all gathered task modules if task_modules: celery.autodiscover_tasks(task_modules) app.logger.info(f"[Celery] Autodiscovered tasks in: {task_modules}") return celery # Immediately bootstrap Celery whenever this module is imported from app import create_app _flask_app = create_app() init_celery(_flask_app)