dingdanquanliucheng/backend/app/core/cache.py
taiyi 0adccb60d2 feat: 新增 Redis 查询缓存加速
新建 cache.py 缓存工具模块,封装 Redis 读写和容错降级。
订单详情/列表、客户列表、定价规则读取走缓存,写操作后精确清除。
Redis 不可用时自动降级查 DB,不影响正常业务。

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-31 10:37:51 +08:00

106 lines
2.9 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.

"""Redis 缓存工具模块。
提供 Redis 连接管理和缓存读写操作,所有操作在 Redis 不可用时静默降级。
被 OrderService、CustomerService、pricing 路由等调用。
"""
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}"