from fastapi_cache import FastAPICache from fastapi_cache.backends.inmemory import InMemoryBackend from fastapi_cache.decorator import cache from app.config import CACHE_TTL import logging from app.core.formatting import LogFormatter from typing import Optional, Any logger = logging.getLogger(__name__) class CustomInMemoryBackend(InMemoryBackend): def __init__(self): """Initialize the cache backend""" super().__init__() self.cache = {} async def delete(self, key: str) -> bool: """Delete a key from the cache""" try: if key in self.cache: del self.cache[key] return True return False except Exception as e: logger.error( LogFormatter.error(f"Failed to delete key {key} from cache", e) ) return False async def get(self, key: str) -> Any: """Get a value from the cache""" return self.cache.get(key) async def set(self, key: str, value: Any, expire: Optional[int] = None) -> None: """Set a value in the cache""" self.cache[key] = value def setup_cache(): """Initialize FastAPI Cache with in-memory backend""" try: logger.info(LogFormatter.section("CACHE INITIALIZATION")) FastAPICache.init(backend=CustomInMemoryBackend(), prefix="fastapi-cache") logger.info(LogFormatter.success("Cache initialized successfully")) except Exception as e: logger.error(LogFormatter.error("Failed to initialize cache", e)) raise async def invalidate_cache_key(key: str): """Invalidate a specific cache key""" try: backend = FastAPICache.get_backend() if hasattr(backend, "delete"): await backend.delete(key) logger.info(LogFormatter.success(f"Cache invalidated for key: {key}")) else: logger.warning( LogFormatter.warning("Cache backend does not support deletion") ) except Exception as e: logger.error(LogFormatter.error(f"Failed to invalidate cache key: {key}", e)) def build_cache_key(*args) -> str: """Build a cache key from multiple arguments""" return ":".join(str(arg) for arg in args if arg is not None) def cached(expire: int = CACHE_TTL, key_builder=None): """Decorator for caching endpoint responses Args: expire (int): Cache TTL in seconds key_builder (callable, optional): Custom key builder function """ return cache(expire=expire, key_builder=key_builder)