serial-assistant:daemon 重启后端口不自动重开、期间静默丢日志——自动重连 + 日志缺口标记 #75

Closed
opened 2026-11-04 10:12:19 +08:00 by super_agent_bot · 2 comments
Collaborator

This is by an automated agent, not a human.

来源:PR #74 上的指示(2026-11-04)——「你提出不好用的问题,然后给出改进建议,这都体现在工单中」,然后改进 serial-assistant。本工单 = 问题登记 + 改进建议;修复 PR 见本工单回帖。

问题(台架实证,阶段 16 网络回归 2026-11-03/04)

那一轮抓板端日志走 serial-assistant daemon,daemon 中途重启过一次,重启后 status.port.ready: false,且不会自己把端口重新打开;从重启点到发现为止,板子吐的字节全部静默丢失,那一轮的板端日志就是这么丢的,被迫改用 pyserial 直读 COM3 重跑。

根因(对照 .dsh/skills/serial-assistant/scripts/serial_tool.py,master 2b5eb1c,v1.1.0-skill)

  1. daemon 启动不恢复开口意图,还先把它抹掉:Daemon.run()(:655)第一件事就是 self._save_meta()(:657),而新实例 port_name=None(__init__ :274),于是 meta.json 被立即改写成 port: null——上一任 daemon 死在持口状态时,_save_meta()(:309–317)里那份端口/波特率/DTR/RTS 现场在重启瞬间就被清掉;启动流程也没有任何重开动作(state="stopped"),要等人手工再敲一次 open 才恢复采集。
  2. 读写出错后永久躺平,没有自动重连:_port_error()(:400–412)释放端口、置 state="error",只留一句 port released, reopen with 'open';串口环 serial_loop()(:354–388)在 self.ser is None 时纯空转。USB 转串口掉线/重枚举(台架常态)后,即使 CH340 几秒后回来,daemon 也不会自己去把它重新打开。
  3. 日志断档不可见:端口没开时 serial.log 什么都不写,新 daemon 又接着往同一份文件追加,没有任何边界/缺口标记。读日志的一方(agent、verify_log.py、人)分不清「板子全程安静」和「采集器死了」——比丢日志本身更危险,因为它会让残缺日志看起来是完整的。
  4. wait-idle 把「采集器死了」渲染成「板子安静」:端口未开时等待照常计满并返回良性的 reason: no_data,调用方拿不到「这是因为没口可采」的信号(丢日志那一轮的形态正是如此)。

影响

  • 台架长会话里任何一次 daemon 重启(崩溃、被 stop、机器重启后自动拉起)都会让采集静默停摆,直到有人恰好去看 status。
  • 违反 SKILL.md 自己的「抓开机日志铁律」的隐含前提:open 之后采集一直在——中途断流而日志表面连续。

改进建议(与修复 PR 一一对应)

  1. 启动自动重开:读 meta 先于覆写它(修 :657 的顺序问题);若上一任是「开着口死的」(未经显式 close/stop),新 daemon 启动即按 meta 的 port/baud/DTR/RTS 自动重开;显式 close/stop 清除重开意图,之后不重开。
  2. 失败自动重连:_port_error 后串口环不再躺平,按退避自动重试重开(REOPEN_SETTLE_S 起步、倍增、封顶 30 s),直到成功或显式 close。
  3. 日志缺口标记落盘:丢口时写一行 SYS 缺口起点、重开成功时写一行缺口终点(含窗口秒数与尝试次数,注明「该窗口内字节不可找回」),让 serial.log 文件本身可归因断档;daemon 启动也写一行边界(新旧 pid)。
  4. 状态可见:status 新增 auto_reopen(enabled/attempts/last_error/next_retry_in_ms),port 语义拆成 ready(实际)与 desired(意图);wait-idle 在端口未开且自动重开未完成时快速失败并带上 auto-reopen 现场,不再返回 no_data。
  5. 兼容与测试:JSON 只增字段、退出码形状不变(serial-boot-test 先 open 后 wait-idle,不受影响);selftest 新增无头用例(重开意图判定、退避计划、缺口标记、no_data 门);status.daemon.version 升 1.2.0-skill(一台机多副本靠版本辨归属);SKILL.md + 串口助手设计说明.md + 串口助手使用指南.md 同步。

验收标准

  • 无头:selftest 全绿(含新增用例)。
  • 台架实测(按 bench.lock 独占 COM3,速测速放):
    • open 后强杀 daemon(模拟崩溃)→ 下一次 CLI 调用自动拉起新 daemon 并自动重开口,status.port.ready: true,serial.log 可见「缺口起/缺口止」两行 SYS 标记;
    • 显式 close 后重启 daemon 不自动重开;
    • stop 语义不变(停 daemon 即放手)。
This is by an automated agent, not a human. 来源:[PR #74 上的指示(2026-11-04)](http://100.123.83.113:3001/wandering1/STM32F4-Base/pulls/74#issuecomment-257)——「你提出不好用的问题,然后给出改进建议,这都体现在工单中」,然后改进 serial-assistant。本工单 = 问题登记 + 改进建议;修复 PR 见本工单回帖。 ## 问题(台架实证,阶段 16 网络回归 2026-11-03/04) 那一轮抓板端日志走 serial-assistant daemon,**daemon 中途重启过一次,重启后 `status.port.ready: false`,且不会自己把端口重新打开**;从重启点到发现为止,板子吐的字节全部静默丢失,那一轮的板端日志就是这么丢的,被迫改用 pyserial 直读 COM3 重跑。 ## 根因(对照 `.dsh/skills/serial-assistant/scripts/serial_tool.py`,master 2b5eb1c,v1.1.0-skill) 1. **daemon 启动不恢复开口意图,还先把它抹掉**:`Daemon.run()`(:655)第一件事就是 `self._save_meta()`(:657),而新实例 `port_name=None`(`__init__` :274),于是 meta.json 被立即改写成 `port: null`——上一任 daemon 死在持口状态时,`_save_meta()`(:309–317)里那份端口/波特率/DTR/RTS 现场**在重启瞬间就被清掉**;启动流程也没有任何重开动作(`state="stopped"`),要等人手工再敲一次 `open` 才恢复采集。 2. **读写出错后永久躺平,没有自动重连**:`_port_error()`(:400–412)释放端口、置 `state="error"`,只留一句 `port released, reopen with 'open'`;串口环 `serial_loop()`(:354–388)在 `self.ser is None` 时纯空转。USB 转串口掉线/重枚举(台架常态)后,即使 CH340 几秒后回来,daemon 也不会自己去把它重新打开。 3. **日志断档不可见**:端口没开时 serial.log 什么都不写,新 daemon 又接着往同一份文件追加,**没有任何边界/缺口标记**。读日志的一方(agent、`verify_log.py`、人)分不清「板子全程安静」和「采集器死了」——比丢日志本身更危险,因为它会让残缺日志看起来是完整的。 4. **`wait-idle` 把「采集器死了」渲染成「板子安静」**:端口未开时等待照常计满并返回良性的 `reason: no_data`,调用方拿不到「这是因为没口可采」的信号(丢日志那一轮的形态正是如此)。 ## 影响 - 台架长会话里任何一次 daemon 重启(崩溃、被 stop、机器重启后自动拉起)都会让采集静默停摆,直到有人恰好去看 `status`。 - 违反 SKILL.md 自己的「抓开机日志铁律」的隐含前提:`open` 之后采集一直在——中途断流而日志表面连续。 ## 改进建议(与修复 PR 一一对应) 1. **启动自动重开**:读 meta **先于**覆写它(修 :657 的顺序问题);若上一任是「开着口死的」(未经显式 `close`/`stop`),新 daemon 启动即按 meta 的 port/baud/DTR/RTS 自动重开;显式 `close`/`stop` 清除重开意图,之后不重开。 2. **失败自动重连**:`_port_error` 后串口环不再躺平,按退避自动重试重开(REOPEN_SETTLE_S 起步、倍增、封顶 30 s),直到成功或显式 `close`。 3. **日志缺口标记落盘**:丢口时写一行 SYS 缺口起点、重开成功时写一行缺口终点(含窗口秒数与尝试次数,注明「该窗口内字节不可找回」),让 serial.log 文件本身可归因断档;daemon 启动也写一行边界(新旧 pid)。 4. **状态可见**:`status` 新增 `auto_reopen`(enabled/attempts/last_error/next_retry_in_ms),`port` 语义拆成 `ready`(实际)与 `desired`(意图);`wait-idle` 在端口未开且自动重开未完成时**快速失败**并带上 auto-reopen 现场,不再返回 `no_data`。 5. **兼容与测试**:JSON 只增字段、退出码形状不变(`serial-boot-test` 先 `open` 后 `wait-idle`,不受影响);`selftest` 新增无头用例(重开意图判定、退避计划、缺口标记、no_data 门);`status.daemon.version` 升 `1.2.0-skill`(一台机多副本靠版本辨归属);SKILL.md + `串口助手设计说明.md` + `串口助手使用指南.md` 同步。 ## 验收标准 - 无头:`selftest` 全绿(含新增用例)。 - 台架实测(按 `bench.lock` 独占 COM3,速测速放): - `open` 后强杀 daemon(模拟崩溃)→ 下一次 CLI 调用自动拉起新 daemon **并自动重开口**,`status.port.ready: true`,serial.log 可见「缺口起/缺口止」两行 SYS 标记; - 显式 `close` 后重启 daemon **不**自动重开; - `stop` 语义不变(停 daemon 即放手)。
super_agent_bot added the 进行中 label 2026-11-04 10:12:19 +08:00
Owner

@super_agent_bot 按照你的建议进行修复测试

@super_agent_bot 按照你的建议进行修复测试
Author
Collaborator

收到:按 #75 的 R1–R5 实施(自动重开 + 自动重连 + 缺口标记 + 状态可见),无头 selftest 与 COM3 台架锁下实测,修复 PR 会回帖到本工单。

收到:按 #75 的 R1–R5 实施(自动重开 + 自动重连 + 缺口标记 + 状态可见),无头 selftest 与 COM3 台架锁下实测,修复 PR 会回帖到本工单。 <!-- dsh-superagent:fc216c078c1956ff4f315b3971485a4c -->
wandering1 added the 已完成 label 2026-11-04 11:39:31 +08:00
super_agent_bot was assigned by wandering1 2026-11-04 11:39:38 +08:00
wandering1 removed the 进行中 label 2026-11-04 11:40:12 +08:00
wandering1 moved this to 已完成 in 项目跟踪 on 2026-11-04 11:40:35 +08:00
Sign in to join this conversation.
2 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: wandering1/STM32F4-Base#75