Files
Unraid-AppOps-Gateway-Public/backend/app/services/job_runner.py
T

117 lines
2.9 KiB
Python

from __future__ import annotations
import json
import uuid
from sqlmodel import Session, select
from ..core.time import utc_now
from ..db.models import JobRun
def list_jobs(session: Session):
return session.exec(select(JobRun).order_by(JobRun.started_at.desc())).all()
def get_job(session: Session, job_id: str) -> JobRun | None:
return session.get(JobRun, job_id)
def create_job(
session: Session,
*,
action_id: str,
target: str,
source: str,
risk: str,
policy_decision: str,
steps: list[str],
audit_event_id: str | None = None,
) -> JobRun:
job = prepare_job(
action_id=action_id,
target=target,
source=source,
risk=risk,
policy_decision=policy_decision,
steps=steps,
audit_event_id=audit_event_id,
)
session.add(job)
session.commit()
session.refresh(job)
return job
def prepare_job(
*,
action_id: str,
target: str,
source: str,
risk: str,
policy_decision: str,
steps: list[str],
audit_event_id: str | None = None,
) -> JobRun:
"""Build a job without committing it so admission can be atomic."""
now = utc_now()
return JobRun(
id=f'job-{uuid.uuid4().hex[:12]}',
type=action_id,
status='queued',
source=source,
action_id=action_id,
target=target,
risk=risk,
policy_decision=policy_decision,
steps_json=json.dumps(steps),
progress=0,
started_at=now,
audit_event_id=audit_event_id,
)
def start_job(session: Session, job: JobRun) -> JobRun:
job.status = 'running'
job.started_at = job.started_at or utc_now()
job.progress = 5
session.add(job)
session.commit()
session.refresh(job)
return job
def complete_job(session: Session, job: JobRun, *, status: str, result_summary: str) -> JobRun:
job.status = status
job.finished_at = utc_now()
job.result_summary = result_summary
job.progress = 100 if status == 'succeeded' else job.progress
if job.started_at:
job.duration_ms = int((job.finished_at - job.started_at).total_seconds() * 1000)
session.add(job)
session.commit()
session.refresh(job)
return job
def cancel_job(session: Session, job: JobRun, *, result_summary: str = 'Cancelled by operator.') -> JobRun:
job.status = 'cancelled'
job.finished_at = utc_now()
job.result_summary = result_summary
if job.started_at:
job.duration_ms = int((job.finished_at - job.started_at).total_seconds() * 1000)
session.add(job)
session.commit()
session.refresh(job)
return job
def set_job_progress(session: Session, job: JobRun, progress: int, result_summary: str | None = None) -> JobRun:
job.progress = max(0, min(100, int(progress)))
if result_summary:
job.result_summary = result_summary
session.add(job)
session.commit()
session.refresh(job)
return job