Files
DjangoAdmin_FastAPI_EleVue/core/redis_client.py
T
ClaudeandClaude 64a5504396 feat(phase4): 全部业务模块迁移到 modules/(结构迁移)
- 21 个模块目录(auth/system/dictionary/configuration/cms/member/region/link/notice/job/log/upload/index)
- 每个模块 router.py(合并模块导出多个 router)/schemas.py/service.py/repository.py/models.py
- routers/v1.py 与 routers/__init__.py 改为直接引用 modules,前缀与权限串原样保留
- core/middleware.py 懒加载指向 modules.system.menu / modules.log;core/redis_client.py 指向 modules.job.scheduler
- apps/views|services|forms 全部改为 re-export 垫片
- 迁移后 grep 守门通过:modules/core 无 apps/extensions 残留引用
- 实测登录、27+ 模块接口、写操作 commit、操作日志落库均正常

Co-Authored-By: Claude <noreply@anthropic.com>
2026-08-07 10:13:30 +08:00

80 lines
2.4 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}")
# startup: 初始化定时任务调度器
from modules.job.scheduler import init_scheduler, shutdown_scheduler
job_count = init_scheduler()
logger.info(f"定时任务调度器已启动,加载 {job_count} 个任务")
yield
# shutdown: 关闭调度器
shutdown_scheduler()
# 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)