Files
natureinpots_community/app/celery_app.py
2025-07-09 01:05:45 -05:00

85 lines
3.0 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# File: app/celery_app.py
import os
import json
import importlib
from celery import Celery
# 1) Create the Celery object (broker/backend will be set from our Flask config)
celery = Celery('natureinpots')
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
# 5) Immediately bootstrap Celery with our Flask app so that
# any `celery -A app.celery_app:celery worker --beat` invocation
# will pick up your plugins tasks and schedules.
from app import create_app
_flask_app = create_app()
init_celery(_flask_app)