"""Redis connection management. Redis is disposable acceleration/coordination — caching, rate limiting, distributed locks, and the arq job queue. It is never the system of record. If `REDIS_REQUIRED` is false, the application degrades gracefully (caching becomes a no-op, readiness does not depend on Redis) instead of failing when Redis is unavailable. """ from __future__ import annotations from collections.abc import AsyncGenerator from functools import lru_cache import redis.asyncio as redis_asyncio from redis.asyncio import Redis from app.core.config import get_settings settings = get_settings() @lru_cache def get_redis_pool() -> Redis: return redis_asyncio.from_url( settings.REDIS_URL, encoding="utf-8", decode_responses=True, socket_connect_timeout=2, socket_timeout=2, ) async def get_redis() -> AsyncGenerator[Redis, None]: """FastAPI dependency yielding the shared Redis client.""" yield get_redis_pool() async def redis_is_ready() -> bool: try: client = get_redis_pool() return bool(await client.ping()) except Exception: return False async def close_redis() -> None: client = get_redis_pool() await client.aclose() # type: ignore[attr-defined] # present at runtime; stubs lag redis-py 5.x