Add Redis 7 to Docker Compose with healthcheck and persistence, separate logical DBs for blacklist and cache, singleton redis client helpers, and unit tests with fakeredis.
67 lines
1.8 KiB
Python
67 lines
1.8 KiB
Python
"""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")
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import logging
|
|
from urllib.parse import urlparse, urlunparse
|
|
|
|
import redis
|
|
|
|
from app.config import settings
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
_clients: dict[str, redis.Redis] = {}
|
|
|
|
|
|
def _redis_url_with_db(base_url: str, db_index: int) -> str:
|
|
"""Return *base_url* with its path replaced by ``/{db_index}``."""
|
|
parsed = urlparse(base_url)
|
|
path = f"/{db_index}"
|
|
return urlunparse(
|
|
(parsed.scheme, parsed.netloc, path, "", "", ""),
|
|
)
|
|
|
|
|
|
def _get_client(url: str) -> redis.Redis:
|
|
if url not in _clients:
|
|
_clients[url] = redis.from_url(url, decode_responses=True)
|
|
logger.info("Redis client connected to %s", url)
|
|
return _clients[url]
|
|
|
|
|
|
def get_redis() -> redis.Redis:
|
|
"""Default Redis connection (URL from ``settings.REDIS_URL``)."""
|
|
return _get_client(settings.REDIS_URL)
|
|
|
|
|
|
def get_redis_blacklist() -> redis.Redis:
|
|
"""Redis DB used for JWT revocation (``jti`` keys with TTL)."""
|
|
url = _redis_url_with_db(
|
|
settings.REDIS_URL,
|
|
settings.REDIS_TOKEN_BLACKLIST_DB,
|
|
)
|
|
return _get_client(url)
|
|
|
|
|
|
def get_redis_cache() -> redis.Redis:
|
|
"""Redis DB reserved for shared cache (scores, queues, etc.)."""
|
|
url = _redis_url_with_db(
|
|
settings.REDIS_URL,
|
|
settings.REDIS_CACHE_DB,
|
|
)
|
|
return _get_client(url)
|