"""Enqueue helper — submit a job to the arq queue from the request cycle. A short-lived pool per call keeps things simple (enqueues are rare, admin-driven actions). Redis being down degrades to a clean 503 rather than a crash (graceful degradation).""" import uuid from typing import Any from arq import create_pool from arq.connections import RedisSettings from app.core.config import get_settings from app.core.logging import get_logger from app.domain.errors import DependencyUnavailableError log = get_logger("worker.queue") async def enqueue(function: str, **kwargs: Any) -> str: """Enqueue ``function`` by name, returning the job id. Raises :class:`DependencyUnavailableError` if the queue can't be reached.""" settings = get_settings() try: pool = await create_pool(RedisSettings.from_dsn(str(settings.redis_url))) except Exception as exc: raise DependencyUnavailableError("Task queue (Redis) is unavailable.") from exc try: job = await pool.enqueue_job(function, **kwargs) finally: await pool.aclose() if job is None: raise DependencyUnavailableError("Could not enqueue job.") return str(job.job_id) async def enqueue_enrich(track_id: uuid.UUID) -> None: """Best-effort enqueue of metadata enrichment for a freshly stored track. The track is already persisted, so enrichment is a follow-up, not a barrier: if the queue is unreachable we log and move on (graceful degradation). The track stays ``metadata_status=pending`` and can be re-enriched later. Deferred a few seconds so the caller's DB transaction is committed before the worker looks the track up (the upload request commits only after it returns).""" try: await enqueue("enrich_track", track_id=str(track_id), _defer_by=5) except DependencyUnavailableError: log.warning("enrich_enqueue_failed", track_id=str(track_id))