from __future__ import annotations import json from typing import Any from uuid import uuid4 import redis from app.config import get_settings from app.models.jobs import JobResponse, JobStatus JOB_KEY_PREFIX = "radio:job:" _memory_store: dict[str, dict[str, Any]] = {} def _redis_client() -> redis.Redis | None: try: client = redis.from_url(get_settings().redis_url, decode_responses=True) client.ping() return client except redis.RedisError: return None def _load_raw(job_id: str) -> dict[str, Any] | None: client = _redis_client() if client is not None: raw = client.get(f"{JOB_KEY_PREFIX}{job_id}") if raw is None: return None return json.loads(raw) return _memory_store.get(job_id) def _save_raw(job_id: str, data: dict[str, Any]) -> None: client = _redis_client() if client is not None: client.setex( f"{JOB_KEY_PREFIX}{job_id}", get_settings().job_ttl_seconds, json.dumps(data), ) return _memory_store[job_id] = data def create_job( kind: str, payload: dict[str, Any], *, status: JobStatus = "queued", result: dict[str, Any] | None = None, ) -> str: job_id = str(uuid4()) _save_raw( job_id, { "status": status, "kind": kind, "payload": payload, "result": result, "error": None, }, ) return job_id def get_job(job_id: str) -> JobResponse | None: data = _load_raw(job_id) if data is None: return None return JobResponse( status=data["status"], result=data.get("result"), error=data.get("error"), ) def get_job_record(job_id: str) -> dict[str, Any] | None: return _load_raw(job_id) def update_job( job_id: str, *, status: JobStatus | None = None, result: dict[str, Any] | None = None, error: str | None = None, ) -> None: data = _load_raw(job_id) if data is None: raise KeyError(f"Job not found: {job_id}") if status is not None: data["status"] = status if result is not None: data["result"] = result if error is not None: data["error"] = error _save_raw(job_id, data)