Files
Aether/src/utils/cache_decorator.py
2025-12-10 20:52:44 +08:00

76 lines
2.6 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""缓存装饰器工具"""
import functools
import json
from typing import Any, Callable, Optional
from src.core.logger import logger
from src.clients.redis_client import get_redis_client_sync
def cache_result(key_prefix: str, ttl: int = 60, user_specific: bool = True) -> Callable:
"""
缓存函数结果的装饰器
Args:
key_prefix: 缓存键前缀
ttl: 缓存过期时间(秒)
user_specific: 是否针对用户缓存(从 context.user.id 获取)
"""
def decorator(func: Callable) -> Callable:
@functools.wraps(func)
async def wrapper(*args, **kwargs) -> Any:
redis_client = get_redis_client_sync()
# 如果 Redis 不可用,直接执行原函数
if redis_client is None:
return await func(*args, **kwargs)
# 构建缓存键
try:
# 从 args 中获取 context通常是第一个参数
context = args[0] if args else None
if user_specific and context and hasattr(context, "user") and context.user:
cache_key = f"{key_prefix}:user:{context.user.id}"
else:
cache_key = f"{key_prefix}:global"
# 如果有额外的参数(如 days添加到键中
if hasattr(args[0], "__dict__"):
# 如果是 dataclass 或对象,获取其属性
for attr_name in ["days", "limit"]:
if hasattr(args[0], attr_name):
attr_value = getattr(args[0], attr_name)
cache_key += f":{attr_name}:{attr_value}"
# 尝试从缓存获取
cached = await redis_client.get(cache_key)
if cached:
logger.debug(f"缓存命中: {cache_key}")
return json.loads(cached)
# 执行原函数
result = await func(*args, **kwargs)
# 保存到缓存
try:
await redis_client.setex(
cache_key, ttl, json.dumps(result, ensure_ascii=False, default=str)
)
logger.debug(f"缓存已保存: {cache_key}, TTL: {ttl}s")
except Exception as e:
logger.warning(f"保存缓存失败: {e}")
return result
except Exception as e:
logger.warning(f"缓存处理出错: {e}, 直接执行原函数")
return await func(*args, **kwargs)
return wrapper
return decorator