Files
MathModelAgent/backend/app/services/redis_manager.py
MuWinds 5305754f0b refactor: 重构注释规范、修复类型错误、添加 lint hook 和 CLAUDE.md (#66)
- 后端按 Google Python Style Guide 重构注释,修复 ruff 和 pyright 错误(161→0)
- 前端按 Vue.js Style Guide 重构注释,修复 biome 错误
- 添加 PostToolUse lint hook(ruff + biome 自动检查)
- 更新 CLAUDE.md 覆盖 Commands/Testing/Structure/CodeStyle/GitWorkflow/Boundaries
- 修复 tsconfig.json 废弃的 baseUrl 配置
2026-05-11 23:02:39 +08:00

101 lines
3.6 KiB
Python

"""Redis 管理模块,提供消息发布/订阅和持久化存储。"""
import redis.asyncio as aioredis
from typing import Optional
import json
from pathlib import Path
from app.config.setting import settings
from app.schemas.response import Message
from app.utils.log_util import logger
class RedisManager:
"""Redis 连接管理器,负责消息发布/订阅和任务消息持久化。"""
def __init__(self):
self.redis_url = settings.REDIS_URL
self._client: Optional[aioredis.Redis] = None
# 创建消息存储目录
self.messages_dir = Path("logs/messages")
self.messages_dir.mkdir(parents=True, exist_ok=True)
async def get_client(self) -> aioredis.Redis:
if self._client is None:
self._client = aioredis.Redis.from_url(
self.redis_url,
decode_responses=True,
max_connections=settings.REDIS_MAX_CONNECTIONS,
)
try:
await self._client.ping() # type: ignore[reportGeneralTypeIssues]
logger.info(f"Redis 连接建立成功: {self.redis_url}")
return self._client
except Exception as e:
logger.error(f"无法连接到Redis: {str(e)}")
raise
async def set(self, key: str, value: str):
"""设置Redis键值对"""
client = await self.get_client()
await client.set(key, value)
await client.expire(key, 36000)
async def _save_message_to_file(self, task_id: str, message: Message):
"""将消息保存到文件中,同一任务的消息保存在同一个文件中"""
try:
# 确保目录存在
self.messages_dir.mkdir(exist_ok=True)
# 使用任务ID作为文件名
file_path = self.messages_dir / f"{task_id}.json"
# 读取现有消息(如果文件存在)
messages = []
if file_path.exists():
with open(file_path, "r", encoding="utf-8") as f:
messages = json.load(f)
# 添加新消息
message_data = message.model_dump()
messages.append(message_data)
# 保存所有消息到文件
with open(file_path, "w", encoding="utf-8") as f:
json.dump(messages, f, ensure_ascii=False, indent=2)
logger.debug(f"消息已追加到文件: {file_path}")
except Exception as e:
logger.error(f"保存消息到文件失败: {str(e)}")
# 不抛出异常,确保主流程不受影响
async def publish_message(self, task_id: str, message: Message):
"""发布消息到特定任务的频道并保存到文件"""
client = await self.get_client()
channel = f"task:{task_id}:messages"
try:
message_json = message.model_dump_json()
await client.publish(channel, message_json)
logger.debug(
f"消息已发布到频道 {channel}:mes_type:{message.msg_type}:msg_content:{message.content}"
)
# 保存消息到文件
await self._save_message_to_file(task_id, message)
except Exception as e:
logger.error(f"发布消息失败: {str(e)}")
raise
async def subscribe_to_task(self, task_id: str):
"""订阅特定任务的消息"""
client = await self.get_client()
pubsub = client.pubsub()
await pubsub.subscribe(f"task:{task_id}:messages")
return pubsub
async def close(self):
"""关闭Redis连接"""
if self._client:
await self._client.close()
self._client = None
redis_manager = RedisManager()