59 lines
1.6 KiB
Python
59 lines
1.6 KiB
Python
"""Task status polling endpoint."""
|
|
from flask import Blueprint, jsonify, request
|
|
from celery.result import AsyncResult
|
|
|
|
from app.extensions import celery
|
|
from app.middleware.rate_limiter import limiter
|
|
from app.services.policy_service import (
|
|
PolicyError,
|
|
assert_api_task_access,
|
|
assert_web_task_access,
|
|
resolve_api_actor,
|
|
resolve_web_actor,
|
|
)
|
|
|
|
tasks_bp = Blueprint("tasks", __name__)
|
|
|
|
|
|
@tasks_bp.route("/<task_id>/status", methods=["GET"])
|
|
@limiter.limit("300/minute", override_defaults=True)
|
|
def get_task_status(task_id: str):
|
|
"""
|
|
Get the status of an async task.
|
|
|
|
Returns:
|
|
JSON with task state and result (if completed)
|
|
"""
|
|
try:
|
|
if request.headers.get("X-API-Key", "").strip():
|
|
actor = resolve_api_actor()
|
|
assert_api_task_access(actor, task_id)
|
|
else:
|
|
actor = resolve_web_actor()
|
|
assert_web_task_access(actor, task_id)
|
|
except PolicyError as exc:
|
|
return jsonify({"error": exc.message}), exc.status_code
|
|
|
|
result = AsyncResult(task_id, app=celery)
|
|
|
|
response = {
|
|
"task_id": task_id,
|
|
"state": result.state,
|
|
}
|
|
|
|
if result.state == "PENDING":
|
|
response["progress"] = "Task is waiting in queue..."
|
|
|
|
elif result.state == "PROCESSING":
|
|
meta = result.info or {}
|
|
response["progress"] = meta.get("step", "Processing...")
|
|
|
|
elif result.state == "SUCCESS":
|
|
task_result = result.result or {}
|
|
response["result"] = task_result
|
|
|
|
elif result.state == "FAILURE":
|
|
response["error"] = str(result.info) if result.info else "Task failed."
|
|
|
|
return jsonify(response)
|