""" Simple in-memory job store for the async CV processing pipeline. Since the Python service runs as a single process on Hugging Face Spaces, an in-memory dict is sufficient. Jobs are keyed by job_id (string UUID). Each entry shape: { "status": "PENDING" | "QUEUED" | "PROCESSING" | "COMPLETED" | "FAILED", "queue_position": int | None, # position in queue (1 = next to process) "result": | None, "error": | None, } """ from __future__ import annotations import threading from typing import Optional _lock = threading.Lock() _store: dict[str, dict] = {} _queue_counter = 0 # monotonic counter to assign queue positions def create_job(job_id: str) -> None: with _lock: _store[job_id] = { "status": "PENDING", "queue_position": None, "result": None, "error": None, } def set_queued(job_id: str) -> None: """Mark job as waiting in the Python processing queue.""" global _queue_counter with _lock: _queue_counter += 1 if job_id in _store: _store[job_id]["status"] = "QUEUED" _store[job_id]["queue_position"] = _queue_counter def set_processing(job_id: str) -> None: with _lock: if job_id in _store: _store[job_id]["status"] = "PROCESSING" _store[job_id]["queue_position"] = None # no longer in queue def set_completed(job_id: str, result: dict) -> None: with _lock: _store[job_id] = {"status": "COMPLETED", "result": result, "error": None} def set_failed(job_id: str, error: str) -> None: with _lock: if job_id in _store: _store[job_id]["status"] = "FAILED" _store[job_id]["error"] = error else: _store[job_id] = {"status": "FAILED", "result": None, "error": error} def get_job(job_id: str) -> Optional[dict]: with _lock: return _store.get(job_id)