TaskPulse/backend/app/api/executions.py

100 lines
3.3 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.

"""API router — TaskExecution (reporting + query)."""
from fastapi import APIRouter, Depends, HTTPException, Query
from pydantic import BaseModel
from sqlalchemy import select, func
from sqlalchemy.ext.asyncio import AsyncSession
from app.database import get_db
from app.schemas import ExecutionOut, ExecutionReport
from app.services import ExecutionService, TaskService, AgentService
from app.models import TaskExecution
router = APIRouter(prefix="/api/tasks/{task_id}/executions", tags=["executions"])
class PaginatedExecutions(BaseModel):
items: list[ExecutionOut]
total: int
page: int
page_size: int
@router.post("", response_model=ExecutionOut, status_code=201)
async def report_execution(task_id: int, body: ExecutionReport,
db: AsyncSession = Depends(get_db)):
"""Agent reports execution result for a task."""
# Verify task exists
task_svc = TaskService(db)
task = await task_svc.get(task_id)
if not task:
raise HTTPException(404, "Task not found")
# Verify agent exists and is active
agent_svc = AgentService(db)
agent = await agent_svc.get(task.agent_id)
if not agent:
raise HTTPException(410, "Agent已被删除请重新注册")
if agent.status != "active":
raise HTTPException(403, "Agent已停用无法汇报")
exec_svc = ExecutionService(db)
record = await exec_svc.report_result(
task_id=task_id,
agent_id=task.agent_id,
status=body.status,
finished_at=body.finished_at,
duration_ms=body.duration_ms,
result=body.result,
log=body.log,
error_message=body.error_message,
)
# Update task's last_run info
await task_svc.mark_run(task_id, success=(body.status == "success"))
await db.commit()
return ExecutionOut(**record.__dict__)
@router.get("", response_model=PaginatedExecutions)
async def list_executions(
task_id: int,
page: int = Query(1, ge=1),
page_size: int = Query(20, ge=1, le=100),
db: AsyncSession = Depends(get_db),
):
exec_svc = ExecutionService(db)
offset = (page - 1) * page_size
records = await exec_svc.get_executions(task_id, limit=page_size, offset=offset)
# Get total count
count_stmt = select(func.count()).select_from(TaskExecution).where(TaskExecution.task_id == task_id)
total = (await db.execute(count_stmt)).scalar() or 0
return PaginatedExecutions(
items=[ExecutionOut(**r.__dict__) for r in records],
total=total,
page=page,
page_size=page_size,
)
@router.get("/recent", response_model=list[ExecutionOut])
async def recent_executions(
limit: int = Query(100, ge=1, le=500),
db: AsyncSession = Depends(get_db),
):
"""Get recent executions across all tasks (for dashboard)."""
exec_svc = ExecutionService(db)
records = await exec_svc.get_recent_executions(limit=limit)
return [ExecutionOut(**r.__dict__) for r in records]
@router.get("/{execution_id}", response_model=ExecutionOut)
async def get_execution(execution_id: int, db: AsyncSession = Depends(get_db)):
exec_svc = ExecutionService(db)
record = await exec_svc.get_execution(execution_id)
if not record:
raise HTTPException(404, "Execution not found")
return ExecutionOut(**record.__dict__)