dingdanquanliucheng/backend/app/core/cache.py

106 lines
2.9 KiB
Python
Raw Normal View History

"""Redis 缓存工具模块。
提供 Redis 连接管理和缓存读写操作所有操作在 Redis 不可用时静默降级
OrderServiceCustomerServicepricing 路由等调用
"""
import hashlib
import json
import logging
import redis
from backend.app.core.config import get_settings
logger = logging.getLogger(__name__)
_redis_client: redis.Redis | None = None
def get_redis() -> redis.Redis | None:
"""获取 Redis 连接单例,连接失败时返回 None。"""
global _redis_client
if _redis_client is not None:
return _redis_client
try:
settings = get_settings()
_redis_client = redis.Redis(
host=settings.redis_host,
port=settings.redis_port,
db=settings.redis_db,
password=settings.redis_password or None,
decode_responses=True,
socket_connect_timeout=2,
socket_timeout=2,
)
_redis_client.ping()
logger.info("Redis 连接成功: %s:%s/%s", settings.redis_host, settings.redis_port, settings.redis_db)
return _redis_client
except Exception as exc:
logger.warning("Redis 连接失败,降级为无缓存模式: %s", exc)
_redis_client = None
return None
def cache_get(key: str):
"""读取缓存,返回反序列化后的 dict/list未命中或异常返回 None。"""
try:
r = get_redis()
if r is None:
return None
raw = r.get(key)
if raw is None:
return None
return json.loads(raw)
except Exception:
return None
def cache_set(key: str, data, ttl: int = 60) -> None:
"""写入缓存JSON 序列化后存储并设置 TTL。异常时静默跳过。"""
try:
r = get_redis()
if r is None:
return
r.set(key, json.dumps(data, ensure_ascii=False, default=str), ex=ttl)
except Exception:
pass
def cache_delete(key: str) -> None:
"""精确删除单个缓存 key。"""
try:
r = get_redis()
if r is not None:
r.delete(key)
except Exception:
pass
def cache_delete_pattern(pattern: str) -> None:
"""按模式批量删除缓存SCAN + DELETE"order:list:*""""
try:
r = get_redis()
if r is None:
return
cursor = 0
while True:
cursor, keys = r.scan(cursor=cursor, match=pattern, count=100)
if keys:
r.delete(*keys)
if cursor == 0:
break
except Exception:
pass
def make_cache_key(prefix: str, **params) -> str:
"""生成带参数哈希的缓存 key。
: make_cache_key("order:list", user_id=1, status="draft")
"order:list:a1b2c3d4"
"""
raw = json.dumps(params, sort_keys=True, ensure_ascii=False, default=str)
suffix = hashlib.md5(raw.encode()).hexdigest()[:8]
return f"{prefix}:{suffix}"