"""Redis 连接管理。 承担三类职责:图形验证码、登录失败限流、JWT 登出黑名单。 键名模板统一在 `app.core.constants` 中定义,禁止在业务代码里拼接字符串。 与其他基础设施一致采用**同步客户端**:路由写 `def` 由 FastAPI 放入线程池执行。 若 DB 同步而 Redis 异步,同一请求里就会出现"要么路由必须写 async(于是同步 DB 阻塞事件循环)、要么把 Redis 调用包进 run_in_threadpool"的两难,两头都别扭。 """ from redis import Redis from app.core.config import get_settings _client: Redis | None = None def get_redis() -> Redis: """获取 Redis 客户端单例(首次调用时创建)。 延迟创建:Redis 未启动时不影响应用启动。 返回的是**同步**客户端,直接调用即可,不要 await。 """ global _client if _client is None: settings = get_settings() _client = Redis.from_url( settings.redis_url, encoding="utf-8", decode_responses=True, socket_connect_timeout=3, ) return _client def close_redis() -> None: """关闭连接池。应用退出时调用。""" global _client if _client is not None: _client.close() _client = None