"""Job queue abstraction. Swap Redis for any other backend by implementing this Protocol.""" from __future__ import annotations import uuid from typing import Any, Protocol class JobQueue(Protocol): async def enqueue(self, job_type: str, payload: dict[str, Any]) -> uuid.UUID: """Persist job to DB + push UUID onto queue. Returns the job UUID.""" ... async def dequeue(self, timeout: int = 5) -> tuple[uuid.UUID, str, dict[str, Any]] | None: """Block up to `timeout` seconds for a job. Returns (id, type, payload) or None.""" ... async def mark_running(self, job_id: uuid.UUID) -> None: """Mark a job as running. Called by the worker when it picks up the job.""" ... async def mark_done(self, job_id: uuid.UUID) -> None: """Mark a job as successfully completed.""" ... async def mark_failed(self, job_id: uuid.UUID, error: str) -> None: """Mark a job as failed with an error message. Increments attempt counter.""" ...