Skip to content

fix: 修复 v2.3.0 评审的两处 P1 与 P2 代码卫生项 - #44

Merged
CSJ608 merged 1 commit into
mainfrom
fix-review-p1-session-guarantees
Aug 28, 2026
Merged

CSJ608 merged 1 commit into
mainfrom
fix-review-p1-session-guarantees

Conversation

@CSJ608

@CSJ608 CSJ608 commented Aug 28, 2026

Copy link
Copy Markdown
Owner

对应评审报告:StreamFrame-v2.3.0-代码评审报告.md(已逐条核查,全部属实)。

P1-1 过期故障在 epoch 校验之前发布 Retry 并归零活会话编号

根因:CommunicationStateChanging 的归零/发布都在 Retry 分支 gate 内的 epoch 检查之前执行。迟到的幽灵故障(epoch 已被替换,如垂死会话的第二个 ScheduleReconnect 被 net48 慢速线程池延迟到新会话建立之后)不拆会话,但把活会话的 State 谎报成 Retry、CurrentSessionId 归零——WaitForConnectedAsync 悬挂、活会话绑定发送被误判失效,且无自愈。

修复:Retry + 携带过期 epoch 时,在任何对外可见的发布之前整体丢弃;gate 内权威复查保留(防检查与发布之间的窄竞态)。用户显式 Reconnect()(无 epoch)不受影响。

回归测试:反射调度过期 epoch 的 ScheduleReconnect(公共 API 无法构造延迟到达),断言 State/编号不被污染、活会话发送照常成功——修复前此测试红,修复后绿。

P1-2 残留旧会话绑定条目可能在新会话 socket 上错发并报告成功

根因:StartSession 开头的旧会话清理刻意不清扫挂起条目(保护"Connected 已发布、新会话任务未就绪"窗口内注册的新条目,v2.3.0 开发中 net48 暴露的竞态所需);但 SendWorkerAsync 认领时不校验 SessionId——Connected→Connected 直连拆除路径残留的旧会话排队条目会被新 worker 发到新 socket 并 Complete(),调用方收到"成功"但消息走了错误的会话,直接违反"绝不跨会话重放"。

修复(采纳评审建议的双保险之一):worker 认领时校验 entry.SessionId,不属于当前会话的绑定条目一律以 SessionExpiredException 失败、绝不发送。此校验与清扫互补,闭合一切条目跨会话存活的路径。

测试:压测改为按帧内容对账——每个完整帧的负载必须带本轮标签(r{round}-{i}),任何跨会话/跨轮次错发即刻失败(评审 P2-8 一并解决)。

P2 修复清单

项 修复
P2-5 停机顺序 FaultPendingSessionSends 先于 TryComplete——队满等待中的条目统一 SessionExpiredException,不再偶发 ChannelClosedException
P2-6 异常泄漏 worker 写出失败时 internal SessionFaultException/ObjectDisposedException 收敛为 SessionExpiredException
P2-7 Reconnect 前置校验 先于 Start() 调用由 NRE 改为 InvalidOperationException(XML 文档同步)
P2-1 快照开销 未完成帧超时关闭(默认)时跳过快照拷贝
P2-4 未观察异常 双检窗口失败改为 await 条目携带的同一异常
P2-2 背压盲区文档 选项 XML + README 双语补充:ReceiveQueueCapacity 消费停滞期间超时不计时,内存防线由 MaxIncompleteFrameBufferBytes 兜底
P2-3 接口文档 IStreamConnection.FrameError 补 IncompleteFrameTimeout
P2-9 断言收紧 排队条目失败类型收紧为精确 SessionExpiredException(仅写出中条目保留合法双结局的联合类型)

P2-10(TestHostSetup 抬线程池可能掩盖生产问题)如实接受为已知权衡,不改。

测试

77×3 = 231 全绿(新增 P1-1 回归测试);本地与 CI 矩阵同基线。

P1-1 迟到的过期故障重连(epoch 已被替换)此前在 gate 内 epoch 校验之前就
发布 Retry 并归零 CurrentSessionId——活会话被谎报为重连中、WaitForConnectedAsync
悬挂、活会话编号被误判失效(net48 线程注入慢时可达)。现改为过期故障在任何
对外发布之前整体丢弃;gate 内权威复查保留。反射调度过期故障的回归测试锁定。

P1-2 发送 worker 认领条目时不校验 SessionId,Connected→Connected 直连拆除
(StartSession 内清理刻意不清扫以保护刚注册的新条目)残留的旧会话排队条目
会被新 worker 发到新 socket 并以成功收尾——违反"绝不跨会话重放"的核心保证。
现认领时校验编号:不属于当前会话的绑定条目一律 SessionExpiredException、
绝不发送。压测改为按帧内容对账(负载必须带本轮标签)作为错发探测器。

另修评审 P2 的代码项:停机清扫先于通道完成(统一失败类型)、internal
SessionFaultException/ObjectDisposedException 收敛为 SessionExpired、
Reconnect() 先于 Start() 抛 InvalidOperationException、超时关闭时跳过快照拷贝、
双检窗口以条目同一异常收尾(观察 TCS)。
@CSJ608
CSJ608 merged commit 8906c64 into main Aug 28, 2026
4 checks passed
@CSJ608
CSJ608 deleted the fix-review-p1-session-guarantees branch August 28, 2026 15:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant