Spaces:
Running
Running
| """ | |
| 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": <ProcessorResponse payload dict> | None, | |
| "error": <str> | 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) | |