"""Redis client factories. ``settings.REDIS_URL`` selects the default logical database (usually ``0``). Token blacklist and application cache use separate logical DBs on the same Redis instance (``REDIS_TOKEN_BLACKLIST_DB``, ``REDIS_CACHE_DB``) so keys never collide and TTL policies can differ per workload. Usage:: from app.infrastructure.redis_client import get_redis, get_redis_blacklist get_redis().set("key", "value", ex=300) get_redis_blacklist().setex("blacklist:…", ttl, "1") """ # Enable future language features for compatibility from __future__ import annotations # Import logging import logging # Import urlparse, urlunparse from urllib.parse from urllib.parse import urlparse, urlunparse # Import redis import redis # Import settings from app.config from app.config import settings # Assign logger = logging.getLogger(__name__) logger = logging.getLogger(__name__) # Assign _clients = {} _clients: dict[str, redis.Redis] = {} # Define function _redis_url_with_db def _redis_url_with_db(base_url: str, db_index: int) -> str: """Return *base_url* with its path replaced by ``/{db_index}``.""" # Assign parsed = urlparse(base_url) parsed = urlparse(base_url) # Assign path = f"/{db_index}" path = f"/{db_index}" # Return urlunparse( return urlunparse( (parsed.scheme, parsed.netloc, path, "", "", ""), ) # Define function _get_client def _get_client(url: str) -> redis.Redis: # Check: url not in _clients if url not in _clients: # Assign _clients[url] = redis.from_url(url, decode_responses=True) _clients[url] = redis.from_url(url, decode_responses=True) # Log info: "Redis client connected to %s", url logger.info("Redis client connected to %s", url) # Return _clients[url] return _clients[url] # Define function get_redis def get_redis() -> redis.Redis: """Default Redis connection (URL from ``settings.REDIS_URL``).""" # Return _get_client(settings.REDIS_URL) return _get_client(settings.REDIS_URL) # Define function get_redis_blacklist def get_redis_blacklist() -> redis.Redis: """Redis DB used for JWT revocation (``jti`` keys with TTL).""" # Assign url = _redis_url_with_db( url = _redis_url_with_db( settings.REDIS_URL, settings.REDIS_TOKEN_BLACKLIST_DB, ) # Return _get_client(url) return _get_client(url) # Define function get_redis_cache def get_redis_cache() -> redis.Redis: """Redis DB reserved for shared cache (scores, queues, etc.).""" # Assign url = _redis_url_with_db( url = _redis_url_with_db( settings.REDIS_URL, settings.REDIS_CACHE_DB, ) # Return _get_client(url) return _get_client(url)