Files
Imago/app/workers/redis_client.py
T

85 lines
2.2 KiB
Python

"""
Client Redis partagé — pool de connexions async pour ARQ et Pub/Sub.
Inclut le parsing d'URL Redis centralisé pour éviter la duplication.
"""
from typing import Tuple, Optional
from redis.asyncio import ConnectionPool, Redis
from app.config import settings
_pool: ConnectionPool | None = None
def parse_redis_url(url: str | None = None) -> Tuple[str, int, Optional[str], int]:
"""
Parse une URL Redis en (host, port, password, database).
Format accepté : redis://[user:password@]host[:port][/db]
Retourne ('localhost', 6379, None, 0) si l'URL est vide.
"""
if url is None:
url = settings.REDIS_URL
if not url:
return "localhost", 6379, None, 0
if url.startswith("redis://"):
url = url[8:]
if url.startswith("rediss://"):
url = url[9:]
password: Optional[str] = None
if "@" in url:
auth_part, url = url.rsplit("@", 1)
if ":" in auth_part:
password = auth_part.split(":", 1)[1]
else:
password = auth_part
database = 0
if "/" in url:
host_port, db_str = url.split("/", 1)
if db_str:
try:
database = int(db_str)
except ValueError:
pass
else:
host_port = url
host = "localhost"
port = 6379
if ":" in host_port:
host, port_str = host_port.rsplit(":", 1)
if port_str:
try:
port = int(port_str)
except ValueError:
port = 6379
else:
host = host_port or "localhost"
return host, port, password, database
async def get_redis_pool() -> Redis:
"""Retourne un client Redis avec pool de connexions partagé."""
global _pool
if _pool is None:
host, port, password, database = parse_redis_url()
_pool = ConnectionPool.from_url(
settings.REDIS_URL,
max_connections=20,
decode_responses=True,
)
return Redis(connection_pool=_pool)
async def close_redis_pool() -> None:
"""Ferme proprement le pool de connexions Redis."""
global _pool
if _pool is not None:
await _pool.disconnect()
_pool = None