feat(serial): Step 4 事件推送替代轮询(RFC #3 收官) - #11
Merged
Conversation
Backend:
- New bus.rs: Frame {session, seq, dir, t_mono_ns, t_wall, Arc data} with
per-session seq from 1 shared by TX/RX; FrameBus with bounded
per-subscriber queues (drop-oldest + dropped_before prefix-gap
accounting) and Nagle batching (GUI_DEFAULT 16ms/64KiB/512 frames/4096
queue; lone frame for an idle consumer pushes immediately past a 4ms
anti-storm interval).
- Read loop and send_data publish frames after the buffer write
(dual-write coexistence: log buffer/text+raw recording/stats unchanged,
all golden tests intact).
- New get_logs_snapshot command {epoch, session, entries}; clear_logs
returns a bumped epoch.
Bridge (main.rs): app-lifetime pump thread consumes batches with bounded
blocking recv, decorates (display_text/timestamp) and emits
serial://frames; the wire DTO carries no raw bytes (seq/dir/len +
display text).
Frontend:
- useSerialLogs hook: snapshot alignment, incremental append with rAF
throttling, seq dedupe, session-change resync, epoch guard so a snapshot
racing a clear never resurrects entries, dropped_before placeholder rows,
trim mirroring the backend 1000-entry cap; LogViewer keys rows by
session-seq.
- Rollback switch: localStorage serialEventPush=0 restores the legacy
100ms polling loop.
Tests: 40/40 green (5 new bus unit tests incl. drop-oldest prefix-gap
accounting; harness test asserting contiguous seq across RX/TX through
the real reader thread). Hardware-verified on FTDI loopback: burst
sending, clear-during-stream, search/autoscroll/counters, unplug.
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_4ea154d0-3877-4840-ba49-8f6d3a04a982) |
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 4:FrameBus + Nagle 合批 +
serial://frames桥接(收官步)跟踪 issue:#3(前置:#4、#5、#6、#10)
后端
bus.rs新增:Frame {session, seq, dir, t_mono_ns, t_wall, Arc<[u8]>}——seq 会话内从 1 严格递增、TX/RX 同序列;FrameBus有界订阅队列(满则 drop-oldest +dropped_before前缀缺口计数,读线程零阻塞);Nagle 合批(GUI_DEFAULT16ms/64KiB/512 帧/4096 队列;空闲消费者单帧 ≥4ms 间隔即推)send_data在写缓冲之后 publish(双写存续期:日志缓冲/录制/统计不动,全部 golden 测试原样通过)get_logs_snapshot {epoch, session, entries}初始对齐;clear_logs返回递增 epoch 防快照复活桥接(main.rs)
应用级 pump 线程:有界阻塞 recv → 显示装饰(display_text/时间戳)→
emit("serial://frames");热路径 DTO 不携带原始字节(seq/dir/len + 装饰文本,JSON 体积大幅下降)前端
useSerialLogs:快照对齐 → 增量 append(rAF 节流);seq 去重;session 变更自动重对齐;epoch 不匹配的快照直接丢弃(清空永不复活);dropped_before>0插入「丢失 N 帧」占位行;trim 镜像后端 1000 上限;LogViewer 行键改session-seqlocalStorage serialEventPush=0恢复 100ms 轮询验证
cargo test40/40(bus 5 个单测:seq 单调/会话重置/单帧即推/合批/drop-oldest 缺口对账;harness 集成测试:真实读线程 TX+RX seq 连续无丢无重)后续解锁
Note
Medium Risk
Changes the serial read/send hot path, background pump thread, and frontend log state machine; rollback polling exists but default behavior is new event synchronization logic.
Overview
Replaces the default 100ms full-clone
get_logspolling with an event-driven log path: initialget_logs_snapshotalignment plus incrementalserial://framesbatches from a backend pump thread.Backend adds a
FrameBus(bus.rs) with per-sessionseq(TX/RX share one sequence), bounded subscriber queues (drop-oldest +dropped_before), and Nagle-style batching. RX and TX still write the in-memory log buffer first, then publish to the bus.clear_logsnow returns a monotonic epoch; snapshots carry epoch/session so clears cannot resurrect stale rows. New commandget_logs_snapshot.Frontend
useSerialLogslistens for batches, dedupes byseq, resyncs on session change, rAF-throttles appends, shows overload placeholders whendropped_before > 0, and mirrors the ~1000 entry cap.localStorage serialEventPush=0restores polling. LogViewer row keys usesession-seq/gap_key.Existing
get_logsremains for rollback/export alignment during the dual-write period.Reviewed by Cursor Bugbot for commit 8594c66. Bugbot is set up for automated code reviews on this repo. Configure here.