"""Redis 连接池 + 缓存读写封装 用于 verify-token 的服务/Token 缓存,减少数据库访问。 缓存 Key 约定: mcp:svc:{api_key_hash} → 服务信息(TTL 120s) mcp:tok:{token_hash} → Token 信息(TTL 30s) mcp:tok:miss:{token_hash} → 无效标记,防穿透(TTL 30s) """ import json import redis.asyncio as aioredis from .config import settings _pool: aioredis.Redis | None = None async def get_redis() -> aioredis.Redis: """获取 Redis 连接(进程级单例)。""" global _pool if _pool is None: _pool = aioredis.Redis( host=settings.REDIS_HOST, port=settings.REDIS_PORT, db=settings.REDIS_DB, password=settings.REDIS_PASSWORD, decode_responses=True, ) return _pool async def close_redis() -> None: """关闭 Redis 连接(进程退出时调用)。""" global _pool if _pool is not None: await _pool.aclose() _pool = None async def cache_get(key: str) -> dict | None: """读取 JSON 缓存,返回 dict 或 None。Redis 不可用时返回 None(视为缓存未命中)。""" try: r = await get_redis() raw = await r.get(key) except Exception: return None if raw is None: return None try: return json.loads(raw) except Exception: return None async def cache_set(key: str, value: dict, ttl: int) -> None: """写入 JSON 缓存,带 TTL(秒)。Redis 不可用时静默跳过。""" try: r = await get_redis() await r.setex(key, ttl, json.dumps(value)) except Exception: pass async def cache_delete(*keys: str) -> None: """删除缓存 key。Redis 不可用时静默跳过,缓存会自然过期。""" if not keys: return try: r = await get_redis() await r.delete(*keys) except Exception: pass