from __future__ import annotations import functools from typing import Any, Awaitable, Callable from fastapi import Request from fastapi.responses import ORJSONResponse from src.infrastructure.cache import KeydbCache from src.infrastructure.logger import get_logger from src.presentation.dependencies.cache import get_redis def cached(*, prefix: str) -> Callable: def decorator(func: Callable[..., Awaitable[Any]]): @functools.wraps(func) async def wrapper(*args: Any, **kwargs: Any) -> Any: logger = get_logger() request = kwargs.get('request') if not isinstance(request, Request): for a in args: if isinstance(a, Request): request = a break auth = kwargs.get('auth') user_id = getattr(auth, 'user_id', None) if auth else None if request is None or user_id is None: return await func(*args, **kwargs) cache_key = f'{prefix}:{user_id}' try: redis = get_redis(request) cache = KeydbCache(redis) hit = await cache.get_user(user_id) if hit is not None: logger.debug(f'Cache hit key={cache_key}') return ORJSONResponse(status_code=200, content=hit) except Exception as e: logger.warning(f'Cache read failed key={cache_key} error={e}') return await func(*args, **kwargs) return wrapper return decorator