Skip to content
项目
群组
代码片段
帮助
正在加载...
帮助
为 GitLab 提交贡献
登录
切换导航
U
ubains-module-test
项目
项目
详情
活动
周期分析
仓库
仓库
文件
提交
分支
标签
贡献者
分枝图
比较
统计图
议题
1
议题
1
列表
看板
标记
里程碑
合并请求
0
合并请求
0
CI / CD
CI / CD
流水线
作业
计划
统计图
Wiki
Wiki
代码片段
代码片段
成员
成员
折叠边栏
关闭边栏
活动
分枝图
统计图
创建新议题
作业
提交
议题看板
打开侧边栏
郑晓兵
ubains-module-test
Commits
311403f6
提交
311403f6
authored
8月 05, 2026
作者:
陈泽健
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
docs(device-sim): 更新 HANDOFF - 记录 P0 消息流问题排查进展
Co-Authored-By:
Claude
<
noreply@anthropic.com
>
上级
f670fbd1
隐藏空白字符变更
内嵌
并排
正在显示
1 个修改的文件
包含
87 行增加
和
24 行删除
+87
-24
HANDOFF_设备模拟.md
HANDOFF_设备模拟.md
+87
-24
没有找到文件。
HANDOFF_设备模拟.md
浏览文件 @
311403f6
...
...
@@ -2,7 +2,7 @@
> **生成时间**: 2026-08-05
> **当前分支**: `platform-auto-test`
> **最近提交**: `
63547417` feat(device-sim): 页面优化 - 批量操作 + 实时消息流 + 环境切换
> **最近提交**: `
11ddf7e9` fix(device-sim): 消息记录架构重构 - 消息队列解耦模拟器线程与数据库
---
...
...
@@ -13,9 +13,9 @@
**需求**
: 无纸化设备上报消息格式与真实设备一致。
**实现**
:
-
新增
`build_reboot_response_payload()`
方法
-
新增
`build_reboot_response_payload()`
方法
(无纸化专属字段:appName="无纸化2.0", deviceModel="Pad-10Pro", buildInfo="" 等)
-
新增
`build_heartbeat_payload()`
方法
-
`deviceModel`
:
无纸化
`Pad-10Pro`
,门口屏
`YT-10
`
-
`deviceModel`
:
门口屏
`YT-10`
,无纸化
`Pad-10Pro
`
-
授权码逻辑: 无纸化使用
`paperless_token_prefix`
或将门口屏
`AND-`
替换为
`ANP-`
**修改文件**
:
...
...
@@ -43,20 +43,32 @@
-
`backend/app/services/device_sim_service.py`
-
`backend/app/schemas/device_sim.py`
### 4. ✅ WebSocket 实时消息推送
(已实现,待修复)
### 4. ✅ WebSocket 实时消息推送
**新增端点**
:
`WS /api/device-sim/ws/messages`
**
当前状态**
: 已实现但存在架构问题,暂时禁用
。
**
实现**
: 消息队列消费成功后,通过回调推送消息到前端
。
**修改文件**
:
-
`backend/app/routers/device_sim.py`
— WebSocket 端点
-
`backend/app/services/device_sim_service.py`
—
消息回调(已注释)
-
`backend/app/routers/device_sim.py`
— WebSocket 端点
+ 回调注册
-
`backend/app/services/device_sim_service.py`
—
推送回调接口
### 5. ✅ 前端页面优化
### 5. ✅ 消息记录架构重构(消息队列)
**实现方案**
:
-
引入
`asyncio.Queue(maxsize=10000)`
消息队列
-
模拟器线程只做入队(
`enqueue_message()`
),不涉及数据库
-
主线程异步消费循环(
`message_consumer_loop()`
)写入数据库 + WebSocket 推送
-
消费循环在
`main.py`
的
`lifespan`
中启动
**修改文件**
:
-
`backend/app/services/device_sim_service.py`
— 消息队列 + 消费循环
-
`backend/app/main.py`
— lifespan 启动消费循环
### 6. ✅ 前端页面优化
**新组件**
:
-
`MessageStream.vue`
— 实时消息流组件(终端风格)
-
`MessageStream.vue`
— 实时消息流组件(终端风格
,支持方向过滤/暂停/搜索
)
**增强组件**
:
-
`DeviceList.vue`
— 批量勾选和批量操作按钮
...
...
@@ -67,9 +79,23 @@
-
`CentralSim.vue`
— 同上
-
`ClientSim.vue`
— 同上
### 6. ✅ 代码提交
### 7. ✅ 文档
**新增文档**
:
-
`_PRD_需求优化_消息记录架构重构与实时消息流.md`
— PRD 需求文档
-
`_执行计划_消息记录架构重构与实时消息流.md`
— 执行计划文档
**更新文档**
:
-
`HANDOFF_设备模拟.md`
— 本文件
### 8. ✅ 代码提交
**提交**
:
`63547417`
feat(device-sim): 页面优化 - 批量操作 + 实时消息流 + 环境切换
| 提交 | 说明 |
|------|------|
|
`e4223169`
| 无纸化设备消息体修复 + 环境配置支持无纸化授权码 |
|
`63547417`
| 页面优化 - 批量操作 + 实时消息流 + 环境切换 |
|
`11ddf7e9`
| 消息记录架构重构 - 消息队列解耦模拟器线程与数据库 |
|
`22eb5e22`
| 消息记录架构重构 PRD + 执行计划 + HANDOFF 更新 |
**已推送到远程**
:
`origin/platform-auto-test`
...
...
@@ -77,34 +103,58 @@
## 二、已知问题
### P0 — 消息记录架构问题
### P0 — 消息流页面显示"暂无消息"
**现象**
: 设备启动后显示
`running`
,但
`totalReports: 0`
,
`lastReportedAt: null`
,消息流页面无消息显示。
**现象**
: 上报记录数据库写入失败,
`totalReports`
始终为 0,消息流页面显示"暂无消息"。
**排查过程**
:
1.
确认新代码已部署到容器(
`enqueue_message`
存在于容器内)
2.
确认 MQTT 连接正常,主题订阅成功
3.
确认
`_sync_report_log`
被重写为入队操作
4.
确认
`_message_queue`
在消费循环中运行
5.
确认
`_message_callback`
已注册到 WebSocket 路由
6.
发现
`message_consumer_loop`
日志"消息消费循环已启动"正常输出
7.
但
`_queue_stats`
显示
`enqueued: 0`
,说明
`_sync_report_log`
没有被调用
**根因**
:
`_sync_report_log()`
在模拟器线程中运行,数据库 session 不兼容线程,导致
`Session's transaction has been rolled back`
错误。
**可能根因**
(待验证):
-
模拟器的
`_on_report_callback`
没有被正确设置?但
`set_report_callback`
在
`start_simulator`
中被调用
-
回调函数中,旧代码
`report_callback(**kwargs)`
还存在(第 579-583 行),但它是
`async`
函数且在线程中调用,可能被忽略
-
`_notify_report`
中的
`self._on_report_callback`
可能为
`None`
**临时方案**
: WebSocket 推送已注释,不影响 MQTT 上报。
**建议排查方向**
:
1.
在
`_notify_report`
方法中添加日志,确认是否被调用
2.
在
`_sync_report_log`
方法中添加日志,确认是否被触发
3.
检查
`set_report_callback`
中的 lambda 闭包是否正确传参
4.
删除旧的
`report_callback`
异步函数(第 579-583 行),避免混淆
**正式方案**
: 参见 PRD 和执行计划文档,需要引入消息队列重构。
### P1 — 中控/集控客户端主题确认
**说明**
: 这两类设备使用的旧格式主题,需要确认真实 MQTT 主题。
---
## 三、修改文件清单
### 已提交
(commit 63547417)
### 已提交
| 文件 | 变更类型 | 说明 |
|------|----------|------|
|
`backend/app/routers/device_sim.py`
| 修改 | 批量操作 API + WebSocket 端点 |
|
`backend/app/services/device_sim_service.py`
| 修改 | 批量操作方法 + 消息回调(已注释) |
|
`backend/app/main.py`
| 修改 | lifespan 启动消息消费循环 |
|
`backend/app/routers/device_sim.py`
| 修改 | 批量操作 API + WebSocket 端点 + 回调注册 |
|
`backend/app/services/device_sim_service.py`
| 修改 | 消息队列 + 消费循环 + 批量操作 |
|
`backend/app/schemas/device_sim.py`
| 修改 | BatchOperationRequest/Response |
|
`backend/app/simulators/paperless_simulator.py`
| 修改 | 无纸化专属消息体 |
|
`backend/app/simulators/base_simulator.py`
| 修改 | deviceModel 修正 |
|
`backend/app/simulators/topic_templates.py`
| 修改 | 无纸化新增主题 |
|
`frontend/src/api/deviceSim.ts`
| 修改 | 批量操作 API + WebSocket 连接 |
|
`frontend/src/components/device/DeviceList.vue`
| 修改 | 批量勾选和操作 |
|
`frontend/src/components/device/MessageStream.vue`
| 新增 | 实时消息流组件 |
|
`frontend/src/types/device.ts`
| 修改 | 无纸化授权码字段 |
|
`frontend/src/views/device-sim/DoorSim.vue`
| 修改 | 左右布局重构 |
|
`frontend/src/views/device-sim/PaperlessSim.vue`
| 修改 | 同上 |
|
`frontend/src/views/device-sim/CentralSim.vue`
| 修改 | 同上 |
|
`frontend/src/views/device-sim/ClientSim.vue`
| 修改 | 同上 |
|
`frontend/src/views/device-sim/EnvConfig.vue`
| 修改 | 无纸化授权码配置 |
---
...
...
@@ -112,7 +162,7 @@
| 优先级 | 任务 | 关联文档 | 说明 |
|--------|------|----------|------|
|
**P0**
|
消息记录架构重构 |
`_PRD_需求优化_消息记录架构重构与实时消息流.md`
| 引入消息队列,修复数据库写入和 WebSocket 推送
|
|
**P0**
|
排查消息流"暂无消息"问题 |
`_PRD_需求优化_消息记录架构重构与实时消息流.md`
| 见已知问题分析
|
| P1 | 中控/集控客户端主题确认 | — | 确认真实上报/订阅主题 |
| P2 | 环境配置统计功能 | — | 统计各环境下的设备数量 |
...
...
@@ -144,11 +194,24 @@
## 七、技术备注
### 模拟器线程模型约束
### 消息队列架构
```
模拟器线程(入队) 主线程异步循环(消费)
┌──────────────────┐ ┌──────────────────────────┐
│ MQTT 上报 │ │ 消息队列 (asyncio.Queue) │
│ → 回调触发 │ ────────▶ │ → 写入数据库 │
│ → 入队(非阻塞) │ │ → WebSocket 推送 │
└──────────────────┘ └──────────────────────────┘
```
### 关键代码位置
-
模拟器必须使用
`sync_playwright`
同步 API(Windows 限制)
-
模拟器在独立线程中运行,不能直接使用主线程的数据库 session
-
解决方案:使用消息队列解耦
-
消息队列定义:
`device_sim_service.py`
第 34-60 行
-
入队函数:
`device_sim_service.py`
第 62-76 行 (
`enqueue_message`
)
-
消费循环:
`device_sim_service.py`
末尾 (
`message_consumer_loop`
)
-
消费循环启动:
`main.py`
lifespan 中
-
WebSocket 回调注册:
`device_sim.py`
第 557-577 行 (
`_register_ws_callback`
)
### 消息流组件使用
...
...
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论