from typing import Optional, Any, Dict import json import redis.asyncio as redis from app.core.cache.base import BaseCache from app.config import settings from app.utils.logger import logger class RedisCache(BaseCache): """ Redis cache implementation """ def __init__(self): """Initialize Redis cache""" self.ttl = settings.CACHE_TTL self._client: Optional[redis.Redis] = None async def _get_client(self) -> redis.Redis: """Get hoặc create Redis client""" if self._client is None: try: self._client = redis.Redis( host=settings.REDIS_HOST, port=settings.REDIS_PORT, db=settings.REDIS_DB, password=settings.REDIS_PASSWORD, decode_responses=True ) # Test connection await self._client.ping() logger.info( f"Redis cache initialized", extra={ "host": settings.REDIS_HOST, "port": settings.REDIS_PORT } ) except Exception as e: logger.error(f"Redis connection failed: {e}") raise return self._client async def get(self, key: str) -> Optional[Any]: """Get value từ Redis""" try: client = await self._get_client() value = await client.get(key) if value is not None: logger.debug(f"Redis cache hit: {key}") return json.loads(value) else: logger.debug(f"Redis cache miss: {key}") return None except Exception as e: logger.error(f"Redis get error: {e}") return None async def set(self, key: str, value: Any, ttl: Optional[int] = None) -> bool: """Set value vào Redis""" try: client = await self._get_client() ttl = ttl or self.ttl # Serialize value to JSON serialized = json.dumps(value) await client.setex(key, ttl, serialized) logger.debug(f"Redis cache set: {key} (TTL: {ttl}s)") return True except Exception as e: logger.error(f"Redis set error: {e}") return False async def delete(self, key: str) -> bool: """Delete key từ Redis""" try: client = await self._get_client() result = await client.delete(key) logger.debug(f"Redis cache delete: {key}") return result > 0 except Exception as e: logger.error(f"Redis delete error: {e}") return False async def clear(self) -> bool: """Clear toàn bộ cache (FLUSHDB)""" try: client = await self._get_client() await client.flushdb() logger.info("Redis cache cleared") return True except Exception as e: logger.error(f"Redis clear error: {e}") return False async def exists(self, key: str) -> bool: """Check key tồn tại""" try: client = await self._get_client() result = await client.exists(key) return result > 0 except Exception as e: logger.error(f"Redis exists error: {e}") return False async def get_stats(self) -> Dict[str, Any]: """Get Redis statistics""" try: client = await self._get_client() info = await client.info() return { "type": "redis", "connected": True, "keys": await client.dbsize(), "memory_used": info.get("used_memory_human"), "uptime": info.get("uptime_in_seconds") } except Exception as e: logger.error(f"Redis stats error: {e}") return {"type": "redis", "connected": False, "error": str(e)} async def close(self): """Close Redis connection""" if self._client: await self._client.close() logger.info("Redis connection closed")