feat(server): app 窗口租约, 全部窗口关闭自动停 EtherCAT 循环
PDO 循环起来后 native 侧一直跑, 其 --parent-pid 自清理只覆盖"本服务拉起 的实例死掉"; 浏览器模式关窗后本服务还在、窗口模式复用现成 ecat_native (parent 是别人)这两种常见离开方式都够不着 —— 从站卡在 OP、自旋节拍白占 一个核。现由每个 app 页面与页面服务器的 WebSocket 租约兜底: - esp32_server.py: 新增 GET /ws/app-lease(手写 RFC6455 握手 + 帧泵)。 连接计数归零后隔 3s GRACE 调后端 /api/op/stop 停循环退回 INIT; 断开 感知靠 TCP FIN / Close 帧回显而非心跳(后台标签页节流不误停); 代理 透传时 _note_ecat_loop 记账"循环是否本服务跑起来的", 只停自己确认过 的; /api/shutdown 与 serve_forever 退出路径同步补停(定时器随进程死亡)。 - js/common/app-lease.js: 租约客户端, 3~30s 退避重连, file:// 静默跳过。 - 接入 tabs.html(外壳持有, 内部切标签不断连)与 pages/motor.html(单独 打开时页面自持)。 - 测试: scripts/test_app_lease.py(裸 TCP 全路径, 假 _ecat_post) + scripts/test_app_lease_e2e.mjs(真 Edge headless + 假后端 8091, 不碰 真总线)。README 补设计动机与要点。
This commit is contained in:
@@ -302,6 +302,29 @@ esp32_app.vbs esp32_web.vbs serve.bat 三个启动入口
|
||||
最坏约 24s,所以前端超时给 30s、代理也给 30s)。
|
||||
4. **循环没跑** → 同一个 `/api/motor/start` 起后台 PDO 循环。
|
||||
断线后每 2s 自动重来一遍,中途拔网线再插会自己恢复。
|
||||
- **关掉 app 必停从站**(上面"自动接入"的反向操作,`esp32_server.py` 的
|
||||
`_app_lease_*` 一节):每个 app 页面与页面服务器保持一条 WebSocket
|
||||
(`js/common/app-lease.js` → `GET /ws/app-lease`),**最后一条**租约连接断开
|
||||
(所有 app 窗口关闭)后,服务端调后端 `/api/op/stop` 停 PDO 循环并把从站退回
|
||||
INIT。为什么必须有它:循环在喂从站 1000ms 过程数据看门狗,没人停它就永远
|
||||
卡在 OP、自旋节拍白占一个核;而 native 的 `--parent-pid` 看门狗只覆盖
|
||||
"本服务拉起的实例",浏览器模式关窗后服务还活着、复用现成实例时 parent
|
||||
又是别人,两种常见离开方式都够不着。要点:
|
||||
- 断开感知靠 TCP FIN / Close 帧回显,**不是心跳计时器** —— 后台标签页的
|
||||
定时器节流不会把"挂着后台的 app"误判成已关闭(服务端必须回 Close 回显,
|
||||
否则浏览器拆不掉 TCP,Edge 实测踩过);
|
||||
- 断连后隔 3s GRACE 才停:F5 刷新只断几百毫秒,不该被当成关窗;
|
||||
- 外壳内切标签不停(`tabs.html` 自己持有租约),与 `transport-ecat.teardown`
|
||||
"切到 WiFi 看看不该打断 EtherCAT" 的既有设计一致;
|
||||
- 只停"本服务经代理确认跑过"的循环(`g_ecat_motor_live` 代理记账),
|
||||
直接从 ecat 控制台(:8090)起的循环不动;
|
||||
- 服务进程自己的退出路径(`/api/shutdown`、Ctrl+C)同步补停一次 ——
|
||||
租约定时器随进程死亡,等不到 GRACE 到点。
|
||||
代价:每次重开 app 都要重走 PREOP→SAFEOP→OP,有概率撞 SSC 邮箱楔死
|
||||
(见下一段)—— 这是"关闭必须停"这个要求本身的代价,不是机制缺陷。
|
||||
自测:`python scripts/test_app_lease.py`(服务端逻辑,裸 TCP 全路径)+
|
||||
`node scripts/test_app_lease_e2e.mjs`(真 Edge headless + 真服务器,
|
||||
假后端钉在 8091,绝不碰真总线)。
|
||||
- 接入失败时**必须能看到原因**:横幅与 `#devStatus` 显示归类后的可执行提示
|
||||
(`summarizeLinkError`),完整诊断放在两者的 `title` 里。
|
||||
典型:SSC 邮箱楔死会把 64 条重复 `MailboxError` + SM 现场(2000+ 字符)压成
|
||||
|
||||
Reference in New Issue
Block a user