89 lines
3.1 KiB
Python
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]
|