# ============================================================================= # 企微IT智能服务台 — 超时提醒定时任务 # ============================================================================= # 说明:定时检查超时未回复的会话,发送企微提醒消息 # 运行频率:每 30 秒执行一次 # 超时逻辑: # 1. 坐席回复后 3 分钟员工未回复 -> 发送企微提醒(只发 1 次) # 2. 坐席回复后 10 分钟员工未回复 -> 标记会话为 pending_close # ============================================================================= import logging from datetime import datetime, timedelta from sqlalchemy import select from app.models.conversation import Conversation from app.services.reminder_service import send_reminder_message logger = logging.getLogger(__name__) # 超时配置(分钟) REMINDER_TIMEOUT_MINUTES = 3 # 未回复超时时间 CLOSE_TIMEOUT_MINUTES = 10 # 自动待关闭时间 async def check_unreplied_sessions(): """检查超时未回复的会话,发送提醒并标记待关闭。 此函数由 APScheduler 定时调用(每 30 秒)。 执行流程: 1. 查找需要发送提醒的会话(坐席回复超过3分钟,员工未回复且未发送过提醒) 2. 发送企微提醒消息 3. 标记已发送提醒 4. 查找需要标记待关闭的会话(坐席回复超过10分钟) 5. 更新会话状态为 pending_close """ # 导入数据库 session 工厂 from app.database import _get_session_factory async_session_factory = _get_session_factory() async with async_session_factory() as db: try: # 1. 查找需要发送提醒的会话 # 条件:active 状态 + 有坐席回复 + 超过3分钟未回复 + 未发送过提醒 reminder_threshold = datetime.now() - timedelta(minutes=REMINDER_TIMEOUT_MINUTES) reminder_stmt = select(Conversation).where( Conversation.status == "serving", Conversation.last_agent_reply_at.isnot(None), Conversation.last_agent_reply_at < reminder_threshold, Conversation.reminder_sent == False, ) result = await db.execute(reminder_stmt) sessions_to_remind = result.scalars().all() logger.info(f"发现 {len(sessions_to_remind)} 个需要发送提醒的会话") # 2. 发送企微提醒消息 for session in sessions_to_remind: try: success = await send_reminder_message(session.employee_id) if success: # 3. 标记已发送提醒 session.reminder_sent = True session.reminder_sent_at = datetime.now() logger.info(f"会话 {session.id} 已发送提醒: employee_id={session.employee_id}") else: logger.warning(f"会话 {session.id} 提醒发送失败,跳过") except Exception as e: logger.error(f"会话 {session.id} 发送提醒异常: {e}") continue # 4. 查找需要标记待关闭的会话 # 条件:active 状态 + 有坐席回复 + 超过10分钟未回复 close_threshold = datetime.now() - timedelta(minutes=CLOSE_TIMEOUT_MINUTES) close_stmt = select(Conversation).where( Conversation.status == "serving", Conversation.last_agent_reply_at.isnot(None), Conversation.last_agent_reply_at < close_threshold, ) result = await db.execute(close_stmt) sessions_to_close = result.scalars().all() logger.info(f"发现 {len(sessions_to_close)} 个需要标记待关闭的会话") # 5. 更新会话状态为 pending_close for session in sessions_to_close: session.status = "pending_close" logger.info(f"会话 {session.id} 已标记为待关闭: employee_id={session.employee_id}") # 提交数据库变更 await db.commit() logger.info("超时检查任务执行完成") except Exception as e: await db.rollback() logger.error(f"超时检查任务执行异常: {e}") raise