from __future__ import annotations import os import threading import redis from app.core.config import settings _REDIS_CLIENT: redis.Redis | None = None _LOCK = threading.Lock() def _safe_int(raw_value: object, default: int, minimum: int) -> int: try: parsed = int(raw_value) except Exception: parsed = default return max(minimum, parsed) def _safe_float(raw_value: object, default: float, minimum: float) -> float: try: parsed = float(raw_value) except Exception: parsed = default return max(minimum, parsed) def get_redis() -> redis.Redis: global _REDIS_CLIENT with _LOCK: if _REDIS_CLIENT is not None: return _REDIS_CLIENT pool = redis.BlockingConnectionPool( host=settings.redis_host, port=settings.redis_port, password=settings.redis_password or None, db=settings.redis_db, decode_responses=True, socket_connect_timeout=5, socket_timeout=5, health_check_interval=_safe_int(os.getenv("DOMAIN_API_REDIS_HEALTH_CHECK_INTERVAL", "30"), 30, 0), retry_on_timeout=True, max_connections=_safe_int(os.getenv("DOMAIN_API_REDIS_MAX_CONNECTIONS", "32"), 32, 1), timeout=_safe_float(os.getenv("DOMAIN_API_REDIS_POOL_TIMEOUT", "1.5"), 1.5, 0.1), client_name=f"domain-api:{settings.node_code}:{os.getpid()}", ) _REDIS_CLIENT = redis.Redis(connection_pool=pool) return _REDIS_CLIENT def reset_redis_client_for_tests() -> None: global _REDIS_CLIENT with _LOCK: client = _REDIS_CLIENT _REDIS_CLIENT = None if client is not None: try: client.close() except Exception: pass