import json import hashlib from functools import wraps from typing import Any, Callable, Optional from app.core.redis import get_redis import pickle def generate_cache_key(func_name: str, args: tuple, kwargs: dict) -> str: """Generate a unique cache key based on function name and arguments.""" # Create a string representation of args and kwargs key_data = { 'function': func_name, 'args': str(args), 'kwargs': str(sorted(kwargs.items())) } key_string = json.dumps(key_data, sort_keys=True) # Use SHA256 hash for consistent, shorter keys return f"cache:{hashlib.sha256(key_string.encode()).hexdigest()}" def cache(expire_time: int = 3600, key_prefix: Optional[str] = None): """ Decorator to cache function results in Redis. Args: expire_time: Expiration time in seconds (default: 1 hour) key_prefix: Optional prefix for cache keys """ def decorator(func: Callable) -> Callable: @wraps(func) async def wrapper(*args, **kwargs) -> Any: redis_client = await get_redis() # Generate cache key cache_key = generate_cache_key(func.__name__, args, kwargs) if key_prefix: cache_key = f"{key_prefix}:{cache_key}" try: # Try to get from cache cached_result = await redis_client.get(cache_key) if cached_result: # Deserialize and return cached result return pickle.loads(cached_result) # Cache miss - execute function result = await func(*args, **kwargs) # Store result in cache serialized_result = pickle.dumps(result) await redis_client.setex(cache_key, expire_time, serialized_result) return result except Exception as e: # If caching fails, still execute the function print(f"Cache error: {e}") return await func(*args, **kwargs) return wrapper return decorator async def invalidate_cache_pattern(pattern: str): """Invalidate all cache keys matching a pattern.""" redis_client = await get_redis() try: keys = await redis_client.keys(pattern) if keys: await redis_client.delete(*keys) except Exception as e: print(f"Cache invalidation error: {e}") async def clear_all_cache(): """Clear all cache entries.""" redis_client = await get_redis() try: await redis_client.flushdb() except Exception as e: print(f"Cache clear error: {e}")