feat(serial): Step 3 读线程生命周期修复 - #10
Merged
Merged
Conversation
… salvage RFC #3 Step 3: - disconnect() returns the reader JoinHandle and the (bounded, 500ms) join now happens OUTSIDE the big manager lock in the Tauri command, replacing the in-lock 200ms sleep. connect() joins any stale reader defensively, fixing the close->reopen EBUSY race. - Reader-thread death is no longer silent: the error is recorded, the next status poll (1s) flips is_connected=false with connection_error set, and the frontend toasts 'Connection lost: ...' once per transition. ConnectionStatus gains a connection_error field. - Pending partial frames are flushed (salvaged) on ANY reader exit instead of vanishing; new FrameSegmenter::flush(). - Fix scheduled-send zombie state: on disconnect or emptied payload the SendPanel switch now resets instead of showing 'scheduled active' with a dead timer. Tests: 34/34 green (golden_reader_death_is_silent_today replaced by reader_death_marks_connection_lost_and_salvages_pending; new disconnect_returns_joinable_handle_and_reconnect_is_immediate + flush_drains_pending_regardless_of_idle). Hardware-verified: unplug detection + toast + switch reset, replug reconnect, rapid disconnect/reconnect cycles, recording/export regression.
Bugbot couldn't run - usage limit reachedBugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit. A user or team admin can review and increase usage limits in the Cursor dashboard. (requestId: serverGenReqId_8937df3d-8a14-48a5-a8d2-87356143fe6f) |
This was referenced Sep 2, 2026
Merged
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
RFC #3 Step 3:读线程生命周期
跟踪 issue:#3(前置:#4、#5、#6)
改动
后端
disconnect()返回读线程JoinHandle,bounded join(500ms,is_finished轮询)移到 Tauri 命令层、大锁外执行,取代原锁内 200ms sleep;join 超时则 detach 不阻塞 UIconnect()开头防御性 join 残留读线程 → close→reopen EBUSY 竞态根治is_connected=false且ConnectionStatus新增connection_error字段;惰性清理写句柄与录制FrameSegmenter::flush()打捞残留分帧,尾部数据不再蒸发前端
验证
cargo test34/34 全绿,零警告;npm run build通过golden_reader_death_is_silent_today(钉住旧坏行为)→reader_death_marks_connection_lost_and_salvages_pending(钉住新行为);新增 reconnect 竞态测试与flush单测范围外
Note
Medium Risk
Changes core serial connection lifecycle (thread join timing, lazy disconnect on reader death, and reconnect races); mistakes could block polling or leave ports stuck, though bounded join and tests mitigate this.
Overview
Implements RFC #3 Step 3 so serial read-thread shutdown, fatal errors, and reconnect behave correctly instead of leaving a “connected” UI or dropping tail bytes.
Backend:
disconnect()now returns the readerJoinHandleand does fast cleanup under the manager lock; bounded join (500ms) runs in the Tauridisconnect_portcommand after releasing the lock (replacing a lock-held 200ms sleep).connect()joins any stale reader before reopen to avoid EBUSY on quick replug. Fatal read errors are stored on the reader thread;get_statuslazily marks the session disconnected, exposes newconnection_erroronConnectionStatus, and tears down the port/recording. On any reader exit,FrameSegmenter::flush()emits buffered RX so partial frames are not lost.Frontend: Status polling shows a one-time toast when transitioning from connected to disconnected with
connection_error(manual disconnect has no error).SendPanelturns off scheduled sending when disconnected or the payload is cleared, fixing a “scheduled active” zombie state. EN/zh-CN strings added for connection loss.Reviewed by Cursor Bugbot for commit 4cf035c. Bugbot is set up for automated code reviews on this repo. Configure here.