| import asyncio |
| import uuid |
| from datetime import datetime |
|
|
| |
| try: |
| from utils.job_queue import create_job |
| except Exception: |
| create_job = None |
|
|
|
|
| |
| |
| |
|
|
| def normalize_context(context): |
| if isinstance(context, dict): |
| return { |
| "items": context.get("items", []), |
| "webhook": context.get("webhook"), |
| "mode": context.get("mode", "sequential") |
| } |
| return { |
| "items": getattr(context, "items", []), |
| "webhook": getattr(context, "webhook", None), |
| "mode": getattr(context, "mode", "sequential") |
| } |
|
|
|
|
| |
| |
| |
|
|
| async def execute_single(task_name, payload): |
| """ |
| Uses registry executor if available, otherwise returns structured fallback. |
| """ |
|
|
| try: |
| from core.execution.executor import execute_task |
|
|
| return await execute_task( |
| task_name, |
| payload |
| ) |
|
|
| except Exception as e: |
| return { |
| "task": task_name, |
| "status": "failed", |
| "error": str(e) |
| } |
|
|
|
|
| |
| |
| |
|
|
| async def run(context): |
|
|
| ctx = normalize_context(context) |
| items = ctx["items"] |
|
|
| if not items: |
| return { |
| "status": "error", |
| "message": "Batch requires 'items' list" |
| } |
|
|
| batch_id = str(uuid.uuid4()) |
| started_at = datetime.utcnow().isoformat() |
|
|
| results = [] |
| failed = 0 |
|
|
| |
| |
| |
|
|
| if ctx["mode"] == "sequential": |
|
|
| for i, item in enumerate(items): |
|
|
| task_name = item.get("task") |
| payload = item.get("payload", {}) |
|
|
| if not task_name: |
| results.append({ |
| "index": i, |
| "status": "skipped", |
| "reason": "missing task" |
| }) |
| continue |
|
|
| result = await execute_single(task_name, payload) |
|
|
| if isinstance(result, dict) and result.get("status") == "failed": |
| failed += 1 |
|
|
| results.append({ |
| "index": i, |
| "task": task_name, |
| "result": result |
| }) |
|
|
| |
| |
| |
|
|
| elif ctx["mode"] == "parallel": |
|
|
| async def run_item(i, item): |
| task_name = item.get("task") |
| payload = item.get("payload", {}) |
|
|
| if not task_name: |
| return { |
| "index": i, |
| "status": "skipped" |
| } |
|
|
| result = await execute_single(task_name, payload) |
|
|
| return { |
| "index": i, |
| "task": task_name, |
| "result": result |
| } |
|
|
| results = await asyncio.gather( |
| *[run_item(i, item) for i, item in enumerate(items)] |
| ) |
|
|
| else: |
| return { |
| "status": "error", |
| "message": f"Unsupported mode: {ctx['mode']}" |
| } |
|
|
| |
| |
| |
|
|
| job_id = None |
| if create_job: |
| try: |
| job_id = create_job( |
| video_path=None, |
| webhook=ctx["webhook"], |
| metadata={ |
| "batch_id": batch_id, |
| "total": len(items), |
| "failed": failed |
| } |
| ) |
| except Exception: |
| job_id = None |
|
|
| |
| |
| |
|
|
| return { |
| "status": "success", |
| "batch_id": batch_id, |
| "job_id": job_id, |
| "started_at": started_at, |
| "completed_at": datetime.utcnow().isoformat(), |
| "mode": ctx["mode"], |
| "total": len(items), |
| "failed": failed, |
| "results": results |
| } |