- core/redis_client.py 移除 scheduler 耦合,lifespan 由 core/app.py 组合(Redis→调度器→Redis) - main.py 改从 core.app 导入 create_app - 删除 apps/、extensions/ 目录;utils 删除已迁移垫片与死代码 formatter.py - 新增 deploy/(nginx、supervisor)、scripts/(init_db、seed)、logs/(结构化日志落盘) - core/app.py 接入 core.logger setup_logging - 更新 CLAUDE.md 反映 core/shared/modules 新结构 Co-Authored-By: Claude <noreply@anthropic.com>
73 lines
2.1 KiB
Python
73 lines
2.1 KiB
Python
"""
|
|
Redis客户端核心模块(由 utils/redis_ctx.py 迁移而来)
|
|
|
|
封装 Redis 连接管理和请求级上下文注入:
|
|
- lifespan 中创建连接池,关闭时断开
|
|
- 每个请求通过中间件将 Redis 客户端注入 contextvars
|
|
- 业务代码通过 get_redis() 获取当前请求的 Redis 客户端
|
|
"""
|
|
|
|
import logging
|
|
from contextvars import ContextVar
|
|
from contextlib import asynccontextmanager
|
|
|
|
from fastapi import FastAPI
|
|
from redis.asyncio import Redis
|
|
from redis import asyncio as aioredis
|
|
|
|
from config import REDIS_HOST, REDIS_PORT, REDIS_PASSWORD, REDIS_INDEX, REDIS_AUTH
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
# 请求级 Redis 客户端上下文变量
|
|
_redis_ctx: ContextVar[Redis] = ContextVar('_redis_ctx')
|
|
|
|
|
|
def get_redis() -> Redis:
|
|
"""获取当前请求的 Redis 客户端"""
|
|
return _redis_ctx.get()
|
|
|
|
|
|
def _build_redis_url() -> str:
|
|
"""构建 Redis 连接 URL"""
|
|
if REDIS_AUTH and REDIS_PASSWORD:
|
|
return f"redis://:{REDIS_PASSWORD}@{REDIS_HOST}:{REDIS_PORT}/{REDIS_INDEX}"
|
|
return f"redis://{REDIS_HOST}:{REDIS_PORT}/{REDIS_INDEX}"
|
|
|
|
|
|
async def create_redis_pool() -> Redis:
|
|
"""创建 Redis 异步连接池"""
|
|
redis = await aioredis.from_url(
|
|
_build_redis_url(),
|
|
encoding="utf-8",
|
|
decode_responses=True,
|
|
protocol=2
|
|
)
|
|
return redis
|
|
|
|
|
|
@asynccontextmanager
|
|
async def redis_lifespan(app: FastAPI):
|
|
"""Redis 生命周期管理,替代已废弃的 on_event("startup"/"shutdown")"""
|
|
# startup: 创建连接池
|
|
redis = await create_redis_pool()
|
|
await redis.ping()
|
|
app.state.redis = redis
|
|
print(f"Redis 连接成功 --> {REDIS_HOST}:{REDIS_PORT}/{REDIS_INDEX}")
|
|
logger.info(f"Redis 连接成功: {REDIS_HOST}:{REDIS_PORT}/{REDIS_INDEX}")
|
|
|
|
yield
|
|
|
|
# shutdown: 关闭连接
|
|
await redis.aclose()
|
|
app.state.redis = None
|
|
logger.info("Redis 连接已关闭")
|
|
|
|
|
|
async def redis_middleware(request, call_next):
|
|
"""Redis 上下文注入中间件,每个请求开始时将 Redis 客户端注入 contextvars"""
|
|
redis = getattr(request.app.state, 'redis', None)
|
|
if redis is not None:
|
|
_redis_ctx.set(redis)
|
|
return await call_next(request)
|