Files
hms/docs/discussions/2026-05-14-devtools-freeze-root-cause.md
iven 8f353946e1 fix(mp): T40 UI 审计修复 — 28 项设计系统合规 + 安全加固 + 讨论记录
T40 UI 审计修复(60 页面全覆盖):
- 新增 $acc-d/$wrn-d 渐变中间色变量,修复首页轮播渐变硬编码
- 替换 8 处裸 white 为 $white 设计变量(5 个 SCSS 文件)
- 修复 7 处触摸目标 40/44px → 48px(健康/消息/咨询/预约/首页)
- 3 页面新增 Loading 状态(体征录入/个人中心/就诊人添加)
- statusTag 移除硬编码布局值,改用 SCSS mixin 控制
- 医生端 14 页面架构 Hook 层补充(useThrottledDidShow 替换 useEffect)
- 移除 action-inbox 未使用 import

安全 P0 修复:
- JWT 中间件加固:token 类型校验 + 过期预检 + 类型别名简化
- 速率限制增强:滑动窗口 + 暴力破解防护
- analytics handler 错误处理完善

文档:
- T40 审计报告(24 PASS / 36 PASS_WITH_ISSUES / 0 NEEDS_WORK)
- 5 份 DevTools/性能审计讨论记录
- wiki 症状导航 + 小程序章节更新
2026-05-14 23:12:54 +08:00

123 lines
6.1 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# DevTools 卡死根因分析 — 四专家组深度诊断
> 日期: 2026-05-14 | 参与者: 内存泄漏专家 + 渲染性能专家 + 网络/API专家 + DevTools环境专家
## 背景
微信开发者工具中 HMS 小程序持续卡死:
- 内存从 1283MB 增长到 2290MB+
- 截图功能始终超时mp.screenshot timeout
- 页面导航 30s 超时
- 修复 analytics/batch 422 + auth restore 后,卡死依旧
## 根因链条(四维度交叉验证)
```
DevTools 环境问题(基线内存偏高)
├─ compileHotReLoad=true → 每次文件变化重建编译上下文,旧上下文不释放
├─ minified=true → DevTools 二次压缩 JS每个刷新周期重复执行
└─ prebundle=false → webpack 内存中维护完整依赖图
内存基线已高 → GC 频率升高 → JS 线程长时间占用
网络/API 循环(持续加压)
├─ Redis 不可用 → 限流中间件每请求 2 次 error 日志(日志洪泛)
├─ JWT 中间件每请求 2 次 DB 查询(无缓存)
├─ 首页 Tab 切换并发 6+ 请求 × 2 次 DB = 12-16 次 DB 查询
└─ 咨询长轮询 401 时 token 刷新 + 重试循环
后端压力大 + 前端请求队列积压
内存泄漏(持续增长)
├─ consultation detail messages 数组无上限(只增不减)
├─ request.ts inflightRequests 无超时清理
├─ TrendChart canvas node 卸载后未释放
└─ BLE DataBuffer seenKeys Set 不随数据淘汰清理
内存突破阈值 → GC 暂停 → automator 超时 → 卡死
```
## CRITICAL 问题(共 7 项)
### 1. consultation detail messages 数组无上限
- **文件:** `pages/consultation/detail/index.tsx:70-76`(患者端 + 医生端相同)
- **问题:** 长轮询每 3 秒 `[...prev, ...fresh]` 拼接React state 和 messagesRef 各持一份,无上限
- **影响:** 长时间聊天 5000+ 条 → 5MB+ 双份 → 10MB+
### 2. compileHotReLoad 配置矛盾
- **文件:** `project.config.json:10` vs `project.private.config.json:16`
- **问题:** public 设 falseprivate 覆盖为 true → 热重载开启 → 编译上下文累积
- **影响:** 这是 DevTools 内存增长的最主要贡献者
### 3. minified=true 开发模式多余压缩
- **文件:** `project.config.json:12`
- **问题:** DevTools 层二次压缩 JS每个刷新周期重复执行
- **影响:** 72 个 JS 文件 × 每次刷新重新压缩
### 4. Redis 不可用 → 限流日志洪泛
- **文件:** `crates/erp-server/src/middleware/rate_limit.rs:108,119`
- **问题:** 每个受保护请求 2 次 Redis 连接尝试失败 → 2 条 error 日志
- **影响:** 50 req/s = 100 条/秒 error 日志
### 5. JWT 中间件每请求 2 次 DB 查询无缓存
- **文件:** `crates/erp-auth/src/middleware/jwt_auth.rs:68-77`
- **问题:** fetch_user_department_ids + fetch_permission_data_scopes同一用户每请求都查
- **影响:** 6 并发请求 = 12 次 DB 查询
### 6. 咨询长轮询 Tab 切换后不停止
- **文件:** `pages/consultation/detail/index.tsx:61-88`
- **问题:** DevTools 页面生命周期与真机不同useEffect cleanup 不一定触发
- **影响:** MCP 批量导航时多个轮询叠加
### 7. 健康数据页 14 useState 重渲染风暴
- **文件:** `pages/health/index.tsx`
- **问题:** 14 个 useState + useThrottledDidShow 触发连锁更新
- **影响:** Tab 切换时 React 调和开销大
## HIGH 问题(共 8 项)
| # | 问题 | 文件 | 影响 |
|---|------|------|------|
| H1 | request.ts inflightRequests 无超时清理 | services/request.ts:164 | 挂死请求闭包永久驻留 |
| H2 | TrendChart canvas node 卸载未释放 | components/TrendChart/index.tsx:153 | 每次 Tab 切换 1-5MB canvas 泄漏 |
| H3 | auth store module-level 缓存 logout 不清 | stores/auth.ts:9-14 | 多账户数据残留 |
| H4 | prebundle 禁用 webpack 内存膨胀 | config/dev.ts:6-8 | 大型 chunk 完整依赖图驻留内存 |
| H5 | 首页 6+ 并发 API 请求无优先级 | pages/index/index.tsx:194 | 后端压力叠加 |
| H6 | 长轮询 401 刷新重试循环 | services/request.ts:117-131 | reLaunch 异步期间继续请求 |
| H7 | BLE syncToServer 重试无退避 | services/ble/BLEManager.ts:262 | flush→失败→push back→flush 循环 |
| H8 | base.wxml 68KB 模板体积偏大 | dist/base.wxml | DevTools 解析负担 |
## 立即缓解措施(不改代码)
1. **关闭热重载:** DevTools 设置 → 关闭"文件保存时自动编译"
2. **关闭压缩:** project.config.json → `"minified": false`
3. **定期重启 DevTools:** 每 30 分钟或内存超过 1.5GB
4. **重启后端时配置 fail_close=false:** 避免 Redis 问题阻塞所有请求
## 修复优先级
| 优先级 | 修复项 | 预期效果 | 复杂度 |
|--------|--------|---------|--------|
| P0 | messages 数组加 MAX_STATE_MESSAGES=300 上限 | 消除最大内存泄漏源 | 低 |
| P0 | project.private.config.json compileHotReLoad=false | 降低 DevTools 内存基线 | 极低 |
| P0 | project.config.json minified=false | 消除多余压缩开销 | 极低 |
| P1 | 限流中间件缓存 Redis 连接失败状态5s | 消除日志洪泛 | 中 |
| P1 | JWT 中间件加 DashMap 缓存TTL 60s | 降低 DB 查询量 90% | 中 |
| P1 | 长轮询迁移到 useDidShow/useDidHide 管理 | 防止多实例轮询 | 中 |
| P2 | request.ts inflightRequests 加超时清理 | 防止闭包泄漏 | 低 |
| P2 | TrendChart useEffect 添加 cleanup | 释放 canvas 节点 | 低 |
| P2 | prebundle 启用(重新评估) | 降低 webpack 内存占用 | 低 |
| P3 | BLE DataBuffer seenKeys 同步清理 | 减少 Set 增长 | 低 |
| P3 | auth store logout 清除 module-level 缓存 | 多账户安全 | 极低 |
## 结论
DevTools 卡死是**多重因素叠加**的结果,不是单一 bug
1. DevTools 环境配置(热重载+压缩)抬高了内存基线
2. 后端 Redis 不可用导致日志洪泛 + 无限流保护
3. 前端 consultation detail messages 无上限是最直接的内存泄漏
4. JWT 中间件无缓存导致后端 DB 压力放大
5. 长轮询生命周期管理在 DevTools 中行为异常
**P0 修复后预计内存增长速度降低 70%+DevTools 可稳定运行 1 小时以上。**