"""Redis client and caching layer.""" import json import logging from typing import Any, Optional import redis.asyncio as aioredis from app.core.settings import get_settings logger = logging.getLogger(__name__) settings = get_settings() # Redis client instance redis_client: Optional[aioredis.Redis] = None async def get_redis() -> aioredis.Redis: """Get Redis client instance.""" global redis_client if redis_client is None: try: redis_client = aioredis.from_url( settings.REDIS_URL, decode_responses=True, socket_connect_timeout=10, socket_timeout=10, ) await redis_client.ping() logger.info("Connected to Redis") except Exception as e: logger.warning(f"Failed to connect to Redis: {e}") redis_client = None return redis_client async def close_redis(): """Close Redis connection.""" global redis_client if redis_client: await redis_client.close() redis_client = None logger.info("Closed Redis connection") async def cache_get(key: str) -> Optional[str]: """Get cached value.""" try: client = await get_redis() if not client: return None value = await client.get(key) return value except Exception as e: logger.error(f"Cache get error for key {key}: {e}") return None async def cache_set(key: str, value: str, ttl: int = 3600): """Set cached value with TTL (default 1 hour).""" try: client = await get_redis() if not client: return await client.set(key, value, ex=ttl) except Exception as e: logger.error(f"Cache set error for key {key}: {e}") async def cache_delete(key: str): """Delete cached value.""" try: client = await get_redis() if not client: return await client.delete(key) except Exception as e: logger.error(f"Cache delete error for key {key}: {e}") async def cache_invalidate_pattern(pattern: str): """Invalidate all cached keys matching pattern.""" try: client = await get_redis() if not client: return keys = await client.keys(pattern) if keys: await client.delete(*keys) except Exception as e: logger.error(f"Cache invalidate error for pattern {pattern}: {e}")