编号:B-06 严重级:medium 工作线:broker(internal/broker) 来源:审查 P-16、P-22、P-25 依赖:B-03 (#10)(校验放在入队之前) 被依赖:无
OnSessionEstablish
superseded
PublishDown
ErrNoConnection
nix/c/{id}/down
ErrNotSubscribed
maxRecvBytes
MaxPacketSize - 128
max_receive_bytes
cmd/nixmsg/uplink.go
publishResp
审查 P-22 的其余两点:握手计时器取消归 B-09,认证超时归 B-12。
internal/broker/hooks.go、broker.go(若 B-03 已落地则在其下发模块);cmd/nixmsg/uplink.go(仅 publishResp 一处)。
internal/broker/hooks.go
broker.go
HandleUplink
OnDisconnect
PublishDown(旧 connID)
-race
response_too_large
以下是本次复审各区审查报告的原文段落。A、M、I、P、S 开头的是原始发现编号(A 管理后台与网页、M 消息核心、I 身份认证群在线、P 传输平台部署、S SDK)。解决方案以本 issue 上方的"结论与统一方案"为准;原文里的方案与之不一致时,按上方执行。
lookupConn
q.push
message/push.go:90-99
sdk/go/client.go:133-135
broker.go:202-244
294-306
app/port/port.go:72-74
server.go:455-474
1014-1021
Disconnect
hooks.go:196-211
broker.go:469-480
session.go:128-130
broker.go:211
360-368
OnConnect
context.Background()
hooks.go:70
auth/pool.go:58-74
min(max_receive_bytes, MaxPacketSize)
uplink.go:282-300
303-315
broker.go:316-329
internal/broker/broker.go
复审基线:main 4059a15(2026-09-30)。编号说明、各工作线的合并顺序、共享文件归属见总览 #7。
4059a15
已合入 origin/main 0c9b459。落地提交 91e887b fix: 完成 broker 复审 B-03 至 B-12 (#13)。
0c9b459
91e887b
No dependencies set.
The note is not visible to the blocked user.
编号:B-06 严重级:medium 工作线:broker(internal/broker) 来源:审查 P-16、P-22、P-25
依赖:B-03 (#10)(校验放在入队之前) 被依赖:无
结论与统一方案
OnSessionEstablish钩子(在 mochi 替换同编号客户端之前调用),把该编号当前的旧连接标记为superseded;PublishDown对被标记或不再是当前连接的目标返回ErrNoConnection。消息线按现有"发布失败 1 秒后重推"处理,不会丢。(审查 P-16)PublishDown在目标连接尚未订阅nix/c/{id}/down时返回新的ErrNotSubscribed(包一层ErrNoConnection),避免 mochi 对无订阅者主题静默返回成功。主修复在 C-01(消息线只对已握手连接推送),本条只做兜底。(审查 P-02 的 broker 部分,原文附在 C-01)maxRecvBytes的读写统一加锁或改为原子变量。(审查 P-22 第二点)MaxPacketSize - 128与max_receive_bytes取小),cmd/nixmsg/uplink.go的publishResp复用它,避免 resp 落在两者之间被静默丢弃。(审查 P-25)审查 P-22 的其余两点:握手计时器取消归 B-09,认证超时归 B-12。
改动文件
internal/broker/hooks.go、broker.go(若 B-03 已落地则在其下发模块);cmd/nixmsg/uplink.go(仅publishResp一处)。与其他问题的交互 / 冲突说明
publishResp;生命周期函数归 B-09,HandleUplink归 C-05。验收与测试
OnDisconnect之前PublishDown(旧 connID)返回错误,新连接收不到这一帧。PublishDown返回ErrNotSubscribed。-race下并发 hello 与推送无竞争报告(本机无 CGO 时在 golang 官方镜像里跑)。response_too_large。问题明细(各区审查原文,证据含文件与行号)
[P-16] 带 connID 的 PublishDown 只检查连接存在,不检查是否仍是当前连接:顶号窗口内,旧连接的帧会发给新连接
lookupConn只要在表里找到就算成功。q.push(队列满),OnDisconnect 会一直拖到 worker 腾出位置。这段时间里:message/push.go:90-99),都会发到新连接上。sdk/go/client.go:133-135),两台设备之间很容易撞号,结果被配到错误的请求上。broker.go:202-244、294-306;app/port/port.go:72-74;mochiserver.go:455-474、1014-1021。OnSessionEstablish钩子,它在 mochi 替换客户端之前调用。在里面把该编号当前的旧连接状态标记为superseded(原子布尔);PublishDown遇到被标记的连接返回ErrNoConnection。Disconnect仍按对象断开,不受影响。internal/broker/hooks.go、broker.goPublishDown(旧 connID)返回错误,新连接收不到这一帧。[P-22] broker 连接状态的三处小毛病
OnDisconnect先从表里删掉连接,再按 connID 去找它的握手计时器,自然找不到,所以计时器从来没被取消(hooks.go:196-211、broker.go:469-480、session.go:128-130)。它只能等 30 秒后自己触发,空跑一次全表扫描。maxRecvBytes写入时加锁,PublishDown读取时不加锁(broker.go:211、360-368)。OnConnect用context.Background()做认证(hooks.go:70)。SDK 30 秒超时断开之后,这次 argon2 校验仍会排到并算完;登录风暴时这些废弃请求堆在队列前面,造成拥塞(auth/pool.go:58-74的 acquire 是支持 ctx 的)。maxRecvBytes时加锁(或改成原子变量);internal/broker/hooks.go、broker.go-race下并发执行 hello 和推送。[P-25] resp 大小检查没扣 128 字节包头预算,落在这个窗口里的 resp 整条丢失
min(max_receive_bytes, MaxPacketSize)判断 resp 是否超限,broker 按MaxPacketSize - 128判断。response_too_large,只能等超时。uplink.go:282-300、303-315;broker.go:316-329。cmd/nixmsg/uplink.go、internal/broker/broker.goresponse_too_large。复审基线:main
4059a15(2026-09-30)。编号说明、各工作线的合并顺序、共享文件归属见总览 #7。已合入 origin/main
0c9b459。落地提交91e887bfix: 完成 broker 复审 B-03 至 B-12 (#13)。