# Celery Worker AI 模型缓存初始化失败修复 **日期**: 2026-02-11 **类型**: Bug 修复 + 架构优化 **影响范围**: Celery Worker (AI 任务队列)、AI Provider Factory ## 问题描述 Celery Worker 启动时 AI Provider Factory 缓存初始化失败,导致所有 AI 任务执行时报错: ``` 模型 gpt-4o-mini 不存在或未激活。请检查: 1) 模型是否已同步到数据库 2) 模型是否已启用(is_active=True) ``` 日志显示: ``` AI Provider Factory 初始化完成: 已加载 0 个模型到缓存 ``` ## 根本原因 **容器启动顺序问题 + 内存缓存架构缺陷**: 1. ❌ 使用进程级内存缓存,每个 Celery Worker 独立缓存 2. ❌ Worker 启动时数据库可能还没有模型数据 3. ❌ 多个 Worker 重复缓存,浪费内存 4. ❌ 缓存更新需要重启所有 Worker ## 解决方案 ### 架构升级:从内存缓存迁移到 Redis 缓存 **新架构**: ``` FastAPI App 启动 → 初始化 Redis 缓存(从数据库加载模型) ↓ Celery Worker 启动 → 从 Redis 读取缓存(无需查询数据库) ↓ 任务执行 → 使用 Redis 缓存的模型信息 ``` **优势**: - ✅ 所有 Worker 共享同一份缓存 - ✅ Worker 启动时如果 Redis 有缓存,直接使用 - ✅ 缓存持久化,重启不丢失 - ✅ 支持热更新(刷新缓存无需重启) - ✅ 降低数据库查询压力 ### 1. 整合 Redis 连接管理 (`app/core/cache.py`) 在现有的 `CacheService` 基础上,添加便捷函数: ```python async def get_redis() -> redis.Redis: """获取 Redis 客户端实例(单例模式)""" if cache.client is None: await cache.connect() return cache.client async def close_redis(): """关闭 Redis 连接""" await cache.close() ``` ### 2. 重构 AI Provider Factory (`app/services/ai_providers/factory.py`) **改动**: - 移除内存缓存 `_provider_cache: Dict[str, int]` - 使用 Redis 缓存:`CACHE_KEY = "ai_models:provider_cache"` - 缓存过期时间:`CACHE_TTL = 3600`(1 小时) - 所有方法改为异步:`async def create_provider(...)` **缓存结构**: ```json { "gpt-4o-mini": 1, "gemini-2.5-flash": 3, "dall-e-3": 1, ... } ``` ### 3. 修改 FastAPI 启动逻辑 (`app/main.py`) 在应用启动时初始化 Redis 缓存: ```python async def lifespan(app: FastAPI): # 启动 await init_db() # 初始化 AI Provider Factory 缓存(Redis) async for db in get_session(): await AIProviderFactory.initialize(db) break yield # 关闭 Redis 连接 await close_redis() ``` ### 4. 优化 Celery Worker 初始化 (`app/core/celery_app.py`) **改进**: - 优先从 Redis 读取缓存 - 如果 Redis 缓存不存在,从数据库初始化 - 增加重试次数:3 → 5 次 - 增加重试延迟:2 → 3 秒 - 更详细的错误诊断信息 ```python @worker_ready.connect def initialize_worker(**kwargs): # 1. 尝试从 Redis 读取缓存 cached_data = await redis.get(AIProviderFactory.CACHE_KEY) if cached_data: logger.info("✅ 从 Redis 加载缓存") return # 2. Redis 缓存不存在,从数据库初始化 await AIProviderFactory.initialize(db) ``` ### 5. 更新所有调用点 将同步调用改为异步: ```python # ❌ 旧代码 provider = AIProviderFactory.create_provider(model) # ✅ 新代码 provider = await AIProviderFactory.create_provider(model) ``` **涉及文件**: - `server/app/services/ai_service.py` - `server/app/tasks/ai_tasks.py`(7 处) - `server/scripts/dev/test_aihubmix_provider.py` ## 修改文件 - ✅ 删除:`server/app/core/redis.py` - 重复文件 - ✅ 修改:`server/app/core/cache.py` - 添加 `get_redis()` 和 `close_redis()` 函数 - ✅ 修改:`server/app/services/ai_providers/factory.py` - 改用 Redis 缓存 - ✅ 修改:`server/app/main.py` - 启动时初始化 Redis 缓存 - ✅ 修改:`server/app/core/celery_app.py` - 优化初始化逻辑 - ✅ 修改:`server/app/services/ai_service.py` - 异步调用 - ✅ 修改:`server/app/tasks/ai_tasks.py` - 异步调用(已完成) - ✅ 修改:`server/scripts/dev/test_aihubmix_provider.py` - 异步调用 ## 验证步骤 1. 重启容器: ```bash cd server docker-compose restart app celery-worker-ai celery-worker-export ``` 2. 检查 FastAPI 启动日志: ```bash docker logs jointo-server-app | grep "AI Provider Factory" ``` 应该看到: ``` ✅ AI Provider Factory initialized (Redis cache) ``` 3. 检查 Celery Worker 日志: ```bash docker logs jointo-server-celery-ai | grep "AI Provider Factory" ``` 应该看到: ``` ✅ AI Provider Factory 缓存已从 Redis 加载(Celery Worker) 已加载 21 个模型到缓存 ``` 4. 验证 Redis 缓存: ```bash docker exec jointo-server-redis redis-cli GET "ai_models:provider_cache" ``` 5. 测试 AI 任务执行 ## 影响 **正面影响**: - ✅ 解决了 Worker 启动时缓存为空的问题 - ✅ 所有 Worker 共享缓存,节省内存 - ✅ 支持缓存热更新,无需重启 - ✅ 降低数据库查询压力 **注意事项**: - ⚠️ 依赖 Redis 服务,Redis 不可用时任务会失败 - ⚠️ 缓存有 1 小时过期时间,过期后会自动重新加载 - ⚠️ 需要确保 FastAPI 应用先于 Celery Worker 启动 ## 后续优化建议 1. 实现缓存预热机制(应用启动前确保缓存已就绪) 2. 添加缓存监控和告警 3. 实现缓存降级策略(Redis 不可用时回退到数据库查询) 4. 考虑使用 Redis Sentinel 或 Cluster 提高可用性