提交 3bdacbda authored 作者: 陈泽健's avatar 陈泽健

fix(device-sim): token_api_host 不做 broker 回退 + 配套文档

当环境配置未设置 token_api_host 时,不再回退到 MQTT Broker 地址,
避免批量启动 500+ 设备时全部串行失败挂起。
Co-Authored-By: 's avatarClaude <noreply@anthropic.com>
上级 e220a9d6
# 执行计划:修复全部启动功能失败 — token_api_host 错误回退
> **执行日期**: 2026-08-20
> **关联问题**: [问题分析_token_api_host错误回退导致全部启动失败.md](../问题处理/问题分析_token_api_host错误回退导致全部启动失败.md)
> **预计工时**: 10 分钟
> **风险等级**: 低(单行代码修改,逻辑清晰)
---
## 一、问题摘要
`device_sim_service.py` 第 843 行在获取 `token_api_host` 时,使用了不安全回退逻辑:
```python
token_api_host = config.default_topic_params.get("token_api_host") or config.broker_host
```
当环境配置未设置 `token_api_host` 时,回退到 MQTT Broker 地址,导致门口屏和无纸化模拟器启动时错误地调用 Token API。批量启动 500+ 台设备时,每台串行失败,全部启动功能挂起无法完成。
---
## 二、修复步骤
### 阶段 1:代码修复
**文件:** `backend/app/services/device_sim_service.py` 第 843 行
| 修改前 | 修改后 |
|--------|--------|
| `token_api_host = config.default_topic_params.get("token_api_host") or config.broker_host` | `token_api_host = config.default_topic_params.get("token_api_host")` |
**原理:** 如果环境配置未设置 `token_api_host`,则保持 `None`,模拟器 `start()` 方法判断 `if not token_host:` 为 True,跳过 Token 获取,直接走 MQTT 启动流程,与之前版本行为一致。
### 阶段 2:部署到 5.60 服务器
1. 更新 `deploy_door_http_final.py`,添加 `device_sim_service.py` 到上传列表
2. 执行部署脚本
3. 重启 Docker 容器
4. 验证部署
### 阶段 3:部署后验证
| 验证项 | 方法 | 预期结果 |
|--------|------|----------|
| 健康检查 | `curl http://192.168.5.60/health` | `{"status":"healthy"}` |
| 门口屏全部启动 | 前端页面操作 | 540 台设备全部启动成功 |
| 无纸化全部启动 | 前端页面操作 | 500 台设备全部启动成功 |
| 门口屏单台启动 | 前端页面操作 | 单台设备启动成功 |
| 设备统计 | `GET /api/device-sim/devices/stats` | running 计数正确 |
---
## 三、回滚方案
若部署后出现新问题,可通过 SSH 登录 5.60 服务器执行:
```bash
cd /data/third_party/plat-auto-test/backend/app/services/
# 从备份恢复旧版本
git checkout -- device_sim_service.py
# 或手动将第 843 行改回: token_api_host = config.default_topic_params.get("token_api_host") or config.broker_host
```
---
## 四、完成标准
- [ ] 门口屏"全部启动"可正常启动所有设备
- [ ] 无纸化"全部启动"可正常启动所有设备
- [ ] 环境配置未设置 `token_api_host` 时,设备启动不报错
- [ ] 环境配置设置了 `token_api_host` 时,设备正常获取 Token 并启动
- [ ] 更新 HANDOFF 文档记录本次修复
---
*本文档由 Claude Code 生成,2026-08-20*
\ No newline at end of file
# 问题分析:全部启动功能失败 — token_api_host 错误回退导致批量启动阻塞
> **分析日期**: 2026-08-20
> **相关模块**: 设备模拟(门口屏/无纸化全部启动)
> **问题现象**: 点击"全部启动"后,页面长时间无响应,设备状态不更新
---
## 一、问题描述
点击门口屏或无纸化的"全部启动"按钮后,页面一直处于加载状态,设备未能成功启动。之前版本的"全部启动"功能可以正常工作。
---
## 二、问题复现
1. 设备模拟页面 → 选择门口屏(540 台设备)或 无纸化(500 台设备)
2. 点击"全部启动"按钮
3. 页面显示加载状态,长时间无响应
4. 设备状态未更新为 running
---
## 三、根因分析
### 3.1 代码变更
会话 H 新增了门口屏 Token 获取功能(`door_simulator.py` 重写 `start()` 方法),在 `device_sim_service.py``start_simulator()` 中新增了 `token_api_host` 参数传递逻辑:
```python
# 获取 token_api_host(从环境配置的 default_topic_params 中)
token_api_host = None
if config.default_topic_params:
token_api_host = config.default_topic_params.get("token_api_host") or config.broker_host
```
**问题在第 843 行**`config.default_topic_params.get("token_api_host")` 返回 `None`(环境配置中未设置该字段),然后 `None or config.broker_host``token_api_host` 回退为 MQTT Broker 地址 `192.168.5.44`
### 3.2 服务器环境配置现状
5.60 服务器的环境配置 `default_topic_params` 内容:
```json
{
"room_ids": ["29dcd33aa47797e7d29d79ae6711d597"],
"company_id": "CN-WQF-UBAINS",
"app_token_end": 40,
"conference_id": "1088",
"app_token_start": 1,
"conference_name": "北京展厅会议室",
"app_token_prefix": "AND-IEL"
}
```
**不包含 `token_api_host` 字段**。因此 `token_api_host` 被错误地设为 `"192.168.5.44"`(MQTT Broker 地址,非 Token 接口地址)。
### 3.3 阻塞链路
`batch_start_simulators()` 按设备 ID **串行遍历**`for device_id in device_ids`),每个设备启动时:
```
start_simulator(device_id)
→ 创建 DoorSimulator 实例(传入 token_api_host="192.168.5.44")
→ sim.start()
→ DoorSimulator.start()
→ token_api_host = "192.168.5.44"(非 None,进入 token 获取分支)
→ allocate_app_token() 登记 appToken ✅
→ DoorTokenClient(host="192.168.5.44")
→ POST https://192.168.5.44/exapi/api-android/token/getTokenInfoByToken
→ ❌ 接口不存在/连接失败(Token API 在 192.168.5.48,不在 192.168.5.44)
→ 抛 ValueError,door_simulator.start() 返回 False
→ 记录错误日志,继续下一个设备
```
**540 台门口屏 × 每次失败耗时 ≈ 1-5 秒 = 大量时间浪费**,且所有设备都因 token 获取失败而启动失败。
### 3.4 为什么之前版本正常
之前版本的 `door_simulator.py` 没有重写 `start()` 方法,直接调用 `BaseSimulator.start()`,不涉及 Token 获取,因此不会阻塞。新增 Token 获取功能后,即便 `token_api_host` 未配置,代码也会回退到 `broker_host` 并尝试调用 Token 接口,导致批量启动全部失败。
---
## 四、影响范围
| 功能 | 是否受影响 | 原因 |
|------|-----------|------|
| 门口屏全部启动(500台) | ✅ **严重受影响** | 每台设备串行调用 Token 接口失败,全部启动失败 |
| 无纸化全部启动(500台) | ✅ **受影响** | 无纸化不涉及 Token 获取,但受 `create_simulator` 传入 `token_api_host` 影响? |
| 门口屏单台启动 | ✅ **受影响** | 同样会尝试 Token 获取,但单台用户可感知失败信息 |
| 无纸化/中控/集控客户端单台启动 | ⚠️ 可能受影响 | 需检查是否也触发 Token 获取逻辑 |
---
## 五、修复方案
### 方案 A(推荐):修复 token_api_host 回退逻辑
修改 `device_sim_service.py` 第 843 行,**不要将 `broker_host` 作为 `token_api_host` 的默认值**
```python
# 修复前
token_api_host = config.default_topic_params.get("token_api_host") or config.broker_host
# 修复后
token_api_host = config.default_topic_params.get("token_api_host")
```
这样如果环境配置未设置 `token_api_host`,则 `token_api_host = None``door_simulator.start()``if not token_host:` 判断为 True,跳过 Token 获取,直接走 MQTT 启动流程,与之前版本行为一致。
### 方案 B:在环境配置中添加 token_api_host
在 5.60 服务器的环境配置 `default_topic_params` 中添加 `token_api_host: "192.168.5.48"`。但该方案需要用户手动配置,且不兼容已有环境配置,不推荐。
---
## 六、预防措施
1. **新增参数时避免不安全默认值**`or config.broker_host` 这种回退逻辑假设 Token API 和 MQTT Broker 在同一台服务器,但实际场景中通常是不同服务器
2. **批量操作前增加超时保护**`batch_start_simulators` 串行遍历 500+ 设备,任何一个设备卡住都会导致整个操作挂起,应增加超时或并行控制
3. **环境配置升级脚本**:新增配置字段时,应提供迁移脚本为已有环境配置设置默认值
---
*本文档由 Claude Code 生成,2026-08-20*
\ No newline at end of file
......@@ -840,7 +840,7 @@ class DeviceSimService:
# 获取 token_api_host(从环境配置的 default_topic_params 中)
token_api_host = None
if config.default_topic_params:
token_api_host = config.default_topic_params.get("token_api_host") or config.broker_host
token_api_host = config.default_topic_params.get("token_api_host")
sim = create_simulator(
device_type=simulator.device_type,
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论