| """Redis singleton - single source of truth for Redis connections.""" |
|
|
| import logging |
| import os |
| from typing import TYPE_CHECKING |
|
|
| logger = logging.getLogger(__name__) |
|
|
| if TYPE_CHECKING: |
| import redis |
| import redis.asyncio as aioredis |
|
|
| REDIS_URL = os.getenv("REDIS_URL", "redis://localhost:6379/0") |
| REDIS_HOST = os.getenv("REDIS_HOST", "localhost") |
| REDIS_PORT = int(os.getenv("REDIS_PORT", "6379")) |
| REDIS_PASSWORD = os.getenv("REDIS_PASSWORD", "") |
|
|
| _redis_client: "redis.Redis | aioredis.Redis | None" = None |
| _sync_pool: "redis.ConnectionPool | None" = None |
| _async_pool: "aioredis.ConnectionPool | None" = None |
|
|
|
|
| def get_redis() -> "redis.Redis | None": |
| """Get Redis client with connection pooling. Single source of truth.""" |
| global _redis_client, _sync_pool |
| import redis |
|
|
| |
| if _sync_pool is None: |
| try: |
| _sync_pool = redis.ConnectionPool.from_url( |
| REDIS_URL, |
| max_connections=20, |
| retry_on_timeout=True, |
| health_check_interval=30, |
| ) |
| logger.info("Redis connection pool created (max 20)") |
| except Exception as e: |
| logger.error(f"Redis pool creation failed: {e}") |
| return None |
|
|
| try: |
| _redis_client = redis.Redis(connection_pool=_sync_pool) |
| return _redis_client |
| except Exception as e: |
| logger.error(f"Redis client creation failed: {e}") |
| return None |
|
|
|
|
| def get_redis_async() -> "aioredis.Redis | None": |
| """Get async Redis client for async operations.""" |
| global _redis_client, _async_pool |
| import redis.asyncio as aioredis |
|
|
| if _async_pool is None: |
| try: |
| _async_pool = aioredis.ConnectionPool.from_url( |
| REDIS_URL, |
| max_connections=20, |
| retry_on_timeout=True, |
| health_check_interval=30, |
| ) |
| logger.info("Async Redis connection pool created (max 20)") |
| except Exception as e: |
| logger.error(f"Async Redis pool creation failed: {e}") |
| return None |
|
|
| try: |
| _redis_client = aioredis.Redis(connection_pool=_async_pool) |
| return _redis_client |
| except Exception as e: |
| logger.error(f"Async Redis client creation failed: {e}") |
| return None |
|
|
|
|
| def close_redis(): |
| """Close Redis connection pool.""" |
| global _sync_pool, _async_pool |
| if _sync_pool: |
| try: |
| _sync_pool.disconnect() |
| logger.info("Redis connection pool closed") |
| except Exception as e: |
| logger.error(f"Redis pool close failed: {e}") |
| _sync_pool = None |
| if _async_pool: |
| try: |
| _async_pool.disconnect() |
| logger.info("Async Redis connection pool closed") |
| except Exception as e: |
| logger.error(f"Async Redis pool close failed: {e}") |
| _async_pool = None |
|
|