基线 origin/main 0c9b459。连接下行队列或 mochi outbound 里已经有 msg / resp 时:
origin/main
0c9b459
msg
resp
PublishThenDisconnect
Publish
sentPub
OnPacketSent
PUBLISH
Disconnect
fatal
logout
Broker.Shutdown
select
Close()
serve.go
0x8B
Stop
internal/broker/downlink.go
sendOne
before := st.sentPub.Load()
waitPacketWritten
internal/broker/hooks.go
internal/broker/broker.go
Shutdown
internal/broker/session.go
fatalKick
cmd/nixmsg/serve.go
brk.Shutdown
Close
只改 internal/broker/ 与 cmd/nixmsg/serve.go 里调用 Shutdown 的等待方式,以及对应测试。不改 PublishDown 签名,不恢复固定 Sleep。不要合 feat/fix-3-downlink-deadlock。偏差节 ### 复审修复 R3-02。
internal/broker/
PublishDown
Sleep
feat/fix-3-downlink-deadlock
### 复审修复 R3-02
已在 feat/fix-r3-66-disconnect (a14ca0d) 修复: 带断开下行改按本帧 OnPacketSent (packet id/载荷) 等待, 不再用连接级 sentPub; Shutdown 先排空再发 0x8B 并在 ctx 内等待连接拆掉. go test ./internal/broker/ ./cmd/nixmsg/ 已通过. 已推送, 未合 main.
feat/fix-r3-66-disconnect
a14ca0d
go test ./internal/broker/ ./cmd/nixmsg/
已合入 main:ef46563 (#66);当前 origin/main HEAD a7a6e34。
ef46563
a7a6e34
复查补强已合入 main ca34344 (#66)。sendOne 在取出帧到返回前记 inSend,排空等待不会把正在等大帧名额的帧当成已经安静。有截止时间时排空预留约 1 秒给 0x8B,排空未完成也会用剩余时间等连接拆掉再 Close。
ca34344
inSend
No dependencies set.
The note is not visible to the blocked user.
现象
基线
origin/main0c9b459。连接下行队列或 mochi outbound 里已经有msg/resp时:PublishThenDisconnect在Publish成功后用sentPub比调用前的计数。OnPacketSent对任意PUBLISH都加一。前面那一帧稍后写出就会让等待返回,然后立刻Disconnect。停用、删除、重置密码的fatal,以及logout的响应,可能还在 outbound 里就被套接字关掉。客户端看不到协议规定的先帧后断。令牌侧多半已经清掉,这不是旧令牌继续可用,而是踢线帧丢失。现有 B-04 测试只有空队列单帧。Broker.Shutdown对传入的 context 做了非阻塞select,几乎立刻Close()。serve.go给的 5 秒用不上。有积压时 MQTT 50x8B可能只进了写缓冲就随Stop丢掉。空闲连接的停机测试覆盖不到。位置
internal/broker/downlink.go:sendOne里before := st.sentPub.Load()与waitPacketWritteninternal/broker/hooks.go:OnPacketSent对所有 PUBLISH 增加sentPubinternal/broker/broker.go:Shutdowninternal/broker/session.go的 logout 与fatalKick;cmd/nixmsg/serve.go的brk.Shutdown方案
Publish对应的 packet id,或只在这一帧的OnPacketSent上完成的 channel),不要用连接级sentPub总数。Shutdown在 ctx 截止前等待各连接把0x8B写出或超时,再Close。ctx 已取消时再立即关闭。PublishThenDisconnect,对端应先读到 fatal 或 logout 帧再看到断开。停机时连接上仍有未写出的下行,应能读到0x8B,或在预算用尽时明确失败而不是空等。约束
只改
internal/broker/与cmd/nixmsg/serve.go里调用Shutdown的等待方式,以及对应测试。不改PublishDown签名,不恢复固定Sleep。不要合feat/fix-3-downlink-deadlock。偏差节### 复审修复 R3-02。已在
feat/fix-r3-66-disconnect(a14ca0d) 修复: 带断开下行改按本帧 OnPacketSent (packet id/载荷) 等待, 不再用连接级 sentPub; Shutdown 先排空再发 0x8B 并在 ctx 内等待连接拆掉.go test ./internal/broker/ ./cmd/nixmsg/已通过. 已推送, 未合 main.已合入 main:
ef46563(#66);当前 origin/main HEADa7a6e34。复查补强已合入 main
ca34344(#66)。sendOne在取出帧到返回前记inSend,排空等待不会把正在等大帧名额的帧当成已经安静。有截止时间时排空预留约 1 秒给0x8B,排空未完成也会用剩余时间等连接拆掉再Close。