feat(db): wire jobs router to SQLAlchemy, add cancel endpoint
CI / basic-check (push) Has been cancelled

This commit is contained in:
2026-08-06 16:12:34 +00:00
parent 76886b93d3
commit 54976814fc
+53 -9
View File
@@ -1,19 +1,63 @@
from fastapi import APIRouter, HTTPException import json
from datetime import datetime, timezone
from app.schemas import EntityResponse, Job, ListResponse from fastapi import APIRouter, Depends, HTTPException, Query
from app.services.store import JOBS from sqlalchemy.orm import Session
from app.database import get_db
from app.models import JobModel
from app.schemas import EntityResponse, Job, JobStatus, ListResponse
router = APIRouter(prefix='/jobs', tags=['jobs']) router = APIRouter(prefix='/jobs', tags=['jobs'])
def _to_job(m: JobModel) -> Job:
return Job(
id=m.id, type=m.type, status=m.status,
progress=m.progress, message=m.message, error=m.error,
payload=json.loads(m.payload_json or '{}'),
result=json.loads(m.result_json or 'null'),
created_at=m.created_at,
started_at=m.started_at,
finished_at=m.finished_at,
)
@router.get('', response_model=ListResponse[Job]) @router.get('', response_model=ListResponse[Job])
def list_jobs() -> ListResponse[Job]: def list_jobs(
return ListResponse(count=len(JOBS), items=JOBS) status: JobStatus | None = Query(default=None),
type: str | None = Query(default=None),
db: Session = Depends(get_db),
):
q = db.query(JobModel)
if status:
q = q.filter(JobModel.status == status)
if type:
q = q.filter(JobModel.type == type)
rows = q.order_by(JobModel.created_at.desc()).all()
return ListResponse(count=len(rows), items=[_to_job(r) for r in rows])
@router.get('/{job_id}', response_model=EntityResponse[Job]) @router.get('/{job_id}', response_model=EntityResponse[Job])
def get_job(job_id: str) -> EntityResponse[Job]: def get_job(job_id: str, db: Session = Depends(get_db)):
for item in JOBS: row = db.query(JobModel).filter(JobModel.id == job_id).first()
if item.id == job_id: if not row:
return EntityResponse(item=item)
raise HTTPException(status_code=404, detail='Job not found') raise HTTPException(status_code=404, detail='Job not found')
return EntityResponse(item=_to_job(row))
@router.post('/{job_id}/cancel', response_model=EntityResponse[Job])
def cancel_job(job_id: str, db: Session = Depends(get_db)):
row = db.query(JobModel).filter(JobModel.id == job_id).first()
if not row:
raise HTTPException(status_code=404, detail='Job not found')
if row.status not in ('pending', 'running'):
raise HTTPException(
status_code=409,
detail=f'Cannot cancel job with status {row.status!r}',
)
row.status = 'cancelled'
row.finished_at = datetime.now(timezone.utc)
db.commit()
db.refresh(row)
return EntityResponse(item=_to_job(row))