studio / publisher /tasks /batch.py
Ava2lon's picture
Upload 170 files
345855e verified
Raw
History Blame Contribute Delete
4.51 kB
import asyncio
import uuid
from datetime import datetime
# Optional queue integration (safe fallback if not present)
try:
from utils.job_queue import create_job
except Exception:
create_job = None
# -------------------------------------------------
# CONTEXT NORMALIZER
# -------------------------------------------------
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")
}
# -------------------------------------------------
# SINGLE TASK EXECUTOR WRAPPER
# -------------------------------------------------
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)
}
# -------------------------------------------------
# MAIN BATCH RUNNER
# -------------------------------------------------
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
# -------------------------------------------------
# MODE: SEQUENTIAL EXECUTION
# -------------------------------------------------
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
})
# -------------------------------------------------
# MODE: PARALLEL EXECUTION
# -------------------------------------------------
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 QUEUE INTEGRATION (OPTIONAL)
# -------------------------------------------------
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
# -------------------------------------------------
# FINAL RESPONSE
# -------------------------------------------------
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
}