"""Redis 缓存后端: 笨 KV(CacheBackend 契约);redis 是 optional extra。 降级不在这里做——本类忠实上抛异常,静默降级是 CacheMW 的职责(算法一份)。 """ from __future__ import annotations from typing import Any try: import redis.asyncio as aioredis except ImportError as _exc: # pragma: no cover - 依赖缺失路径 aioredis = None _IMPORT_ERROR = _exc else: _IMPORT_ERROR = None class RedisCache: """基于 redis.asyncio 的 KV;value 为 JSON 字符串,TTL 由调用方传入。""" def __init__(self, client: Any) -> None: if aioredis is None: raise ImportError( "Redis 缓存后端需要 redis 包: pip install 'polygateway[redis]'" ) from _IMPORT_ERROR self._client = client # 注入的客户端归注入方管理: 关掉它会弄死共享同一连接的其他组件 # (与 RedisLimiter/RedisGate 同一纪律) self._owns_client = False @classmethod def from_url(cls, url: str) -> RedisCache: """自建并持有 Redis 客户端(aclose 时代关);共享后端请直接注入 client。""" if aioredis is None: raise ImportError( "Redis 缓存后端需要 redis 包: pip install 'polygateway[redis]'" ) from _IMPORT_ERROR cache = cls(aioredis.from_url(url, decode_responses=True)) cache._owns_client = True return cache async def get(self, key: str) -> str | None: return await self._client.get(key) async def set(self, key: str, value: str, ttl_s: int) -> None: await self._client.set(key, value, ex=ttl_s) async def aclose(self) -> None: """幂等释放自建客户端;注入的客户端归注入方管理。""" if self._owns_client: self._owns_client = False await self._client.aclose()