Files
xiaobaifupan/app/backend/jobs/repository.py
T

89 lines
3.1 KiB
Python

from __future__ import annotations
import json
from dataclasses import dataclass
from datetime import datetime
from typing import Any
from database import ReviewDatabase
@dataclass(frozen=True)
class SQLiteJobRunRepository:
database: ReviewDatabase
def completed(self, job_id: str, idempotency_key: str) -> bool:
with self.database.connect() as connection:
row = connection.execute(
"""
SELECT 1 FROM job_runs
WHERE job_id = ? AND idempotency_key = ? AND status = 'success'
LIMIT 1
""",
(job_id, idempotency_key),
).fetchone()
return row is not None
def start(
self, job_id: str, idempotency_key: str, output_version: str,
metadata: dict[str, Any] | None = None,
) -> int:
now = datetime.now().astimezone().isoformat(timespec="seconds")
with self.database.connect() as connection:
row = connection.execute(
"""
SELECT COALESCE(MAX(attempt), 0) + 1 AS attempt FROM job_runs
WHERE job_id = ? AND idempotency_key = ?
""",
(job_id, idempotency_key),
).fetchone()
cursor = connection.execute(
"""
INSERT INTO job_runs
(job_id, idempotency_key, status, attempt, started_at,
output_version, metadata)
VALUES (?, ?, 'running', ?, ?, ?, ?)
""",
(
job_id, idempotency_key, int(row["attempt"]), now,
output_version,
json.dumps(metadata or {}, ensure_ascii=False, separators=(",", ":")),
),
)
connection.execute(
"""
DELETE FROM job_runs
WHERE id < (SELECT COALESCE(MAX(id), 0) - 20000 FROM job_runs)
AND status != 'running'
"""
)
return int(cursor.lastrowid)
def finish(
self, run_id: int, status: str, elapsed_ms: int,
error_code: str = "", message: str = "",
) -> None:
now = datetime.now().astimezone().isoformat(timespec="seconds")
with self.database.connect() as connection:
connection.execute(
"""
UPDATE job_runs
SET status = ?, finished_at = ?, elapsed_ms = ?,
error_code = ?, message = ?
WHERE id = ?
""",
(status, now, elapsed_ms, error_code, message[:1000], int(run_id)),
)
def recent(self, limit: int = 20) -> list[dict[str, Any]]:
with self.database.connect() as connection:
rows = connection.execute(
"""
SELECT id, job_id, idempotency_key, status, attempt, started_at,
finished_at, elapsed_ms, error_code, message, output_version
FROM job_runs ORDER BY id DESC LIMIT ?
""",
(max(1, min(100, int(limit))),),
).fetchall()
return [dict(row) for row in rows]