
Some checks failed
Deploy to Production, build images and push to Gitea Registry / build_and_push (pull_request) Failing after 1m24s
This commit adds new guidelines for FastAPI and Vue.js development, emphasizing best practices for component structure, API performance, and data handling. It also introduces caching mechanisms using Redis for improved performance and updates the API structure to streamline authentication and user management. Additionally, new endpoints for categories and time entries are implemented, enhancing the overall functionality of the application.
78 lines
2.7 KiB
Python
78 lines
2.7 KiB
Python
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}") |