RIS_AUTO_SYNC_TOAST_STUCK_ISSUE.md 5.1 KB

RIS自动同步Toast卡住问题分析与解决方案

📋 问题描述

在worklist页面,偶尔会出现"正在同步RIS数据"的toast消息一直显示,不消失的问题,严重影响用户体验。

🔍 问题分析

Toast出现机制

  • 位置src/hooks/useRisAutoSync.ts 中的 onSyncStart 回调
  • 代码message.loading('正在同步RIS数据...', 0) - 第二个参数 0 表示不自动消失
  • 触发条件:RIS自动同步开始时

Toast消失机制

  • 位置src/hooks/useRisAutoSync.ts 中的 onSyncComplete 回调
  • 代码messageDestroyRef.current() 关闭loading消息
  • 触发条件:同步完成(成功或失败)后

根本原因

  1. 缺少超时设置src/API/interceptor.ts 中的 axios 实例没有设置 timeout,导致请求可能无限等待
  2. 同步流程卡住:如果 /auth/study/ris API 请求卡住,await syncRis(params) 永远不会完成
  3. 错误处理不完整:卡住的请求不会抛出错误,因此不会触发 onSyncComplete 回调

代码流程分析

sequenceDiagram
    participant Hook as useRisAutoSync
    participant Service as RisSyncService
    participant API as syncRis
    participant Toast

    Hook->>Service: start()
    Service->>API: syncRis() - 卡住
    Note over API: 请求无限等待
    Service->>Service: 等待响应(永远)
    Note over Toast: Toast永远显示

🐛 复现步骤

方法1:使用浏览器开发者工具模拟网络问题(推荐)

  1. 打开浏览器开发者工具

    • F12 或右键选择"检查元素"
    • 切换到 Network 标签页
  2. 设置网络限速

    • 点击网络标签页顶部的设置图标(⚙️)
    • 选择 No throttling 下拉菜单
    • 选择 Offline 或自定义慢速网络:
      • 添加自定义配置:Name: Very Slow 3GDownload: 50kb/sUpload: 50kb/sLatency: 2000ms
  3. 进入worklist页面

    • 登录应用并进入worklist页面
    • 等待RIS自动同步触发(根据配置间隔,通常5分钟)
    • 或者手动触发同步(如果有相关按钮)
  4. 观察现象

    • toast显示"正在同步RIS数据..."
    • 由于网络极慢,请求会卡住
    • toast永远不会消失

方法2:修改代码临时移除超时(开发环境)

// src/API/interceptor.ts 中临时添加
const axiosInstance = axios.create({
  baseURL: API_BASE_URL,
  timeout: 24 * 60 * 60 * 1000, // 24小时超时(实际上无限等待)
  // ... 其他配置
});

方法3:使用Charles/Fiddler等代理工具

  1. 安装代理工具(Charles或Fiddler)
  2. 配置网络代理
  3. 设置断点或延迟
    • /auth/study/ris 请求上设置断点
    • 或者添加延迟规则让请求永远不响应

方法4:服务器端模拟

如果可以访问后端服务器:

  1. 修改后端代码

    • /auth/study/ris 接口故意不返回响应
    • 或者添加很长的处理时间
  2. 重启服务器并测试

🔍 验证问题

要确认问题确实复现,可以:

  1. 检查浏览器Network标签

    • 看到 /auth/study/ris 请求处于 pending 状态
    • 请求没有完成也没有失败
  2. 检查控制台日志

    • 没有看到 [RisSyncService] 同步成功[RisSyncService] 同步失败 日志
    • 同步过程卡在 await syncRis(params) 这一行
  3. 检查UI状态

    • toast消息一直显示
    • 无法关闭应用或切换页面(除非强制刷新)

🛠️ 解决方案

方案1:添加请求超时(已实施)

为 axios 实例添加超时设置,防止请求无限等待。

修改文件src/API/interceptor.ts

const axiosInstance = axios.create({
  baseURL: API_BASE_URL,
  timeout: 30000, // 30秒超时
  // ... 其他配置
});

优点

  • 简单有效,直接解决问题
  • 防止所有API请求无限等待
  • 30秒超时对于同步操作来说是合理的

缺点

  • 所有请求使用相同超时时间,可能不够灵活
  • 对于某些需要更长等待的操作可能不够

方案2:改进错误处理(可选)

在同步服务中添加超时控制,确保即使请求卡住也能触发错误处理。

方案3:添加手动取消机制(可选)

允许用户手动取消正在进行的同步操作。

💡 验证修复效果

修复后,可以通过以下方式验证:

  1. 设置短超时:将axios timeout设置为5000ms(5秒)
  2. 重复复现步骤
  3. 观察结果:5秒后toast应该消失,并显示错误消息

📝 实施记录

  • 问题发现时间:2025-11-07
  • 问题分析时间:2025-11-07
  • 修复方案:添加axios全局超时设置(30秒)
  • 修复时间:2025-11-07
  • 验证状态:修复已实施,待测试验证

🔗 相关文件

  • src/hooks/useRisAutoSync.ts - 自动同步Hook
  • src/services/risSync/RisSyncService.ts - 同步服务
  • src/API/interceptor.ts - axios配置(已修改)
  • src/API/patient/risActions.ts - RIS API接口

文档版本:1.0.0 创建日期:2025-11-07 作者:系统维护者