fix: 完成 broker 复审 B-03 至 B-12
每连接异步下发与背压、写出后断开、校验当前连接与订阅、生命周期串行、登录条件更新、闲置按在线计、认证超时并发与 Shutdown 0x8B。
This commit is contained in:
@@ -1207,3 +1207,75 @@ issue #3 未关闭,`feat/fix-3-downlink-deadlock` 未合入 `main`。下面是
|
||||
- 原因:默认 info 下第二个 CONNECT、3.1.1 发到错误主题等会把整包写入 JSON 日志。
|
||||
- 备选方案:改 mochi 日志调用点(需 fork)。
|
||||
- 影响:排障时看不到载荷与密码,只见摘要。
|
||||
|
||||
### 复审修复 B-03
|
||||
|
||||
- 日期:2026-09-30
|
||||
- 原条款:DEVELOPMENT 第 5 节每端串行队列;Gitea #10。不改 `PublishDown` 签名。
|
||||
- 实际做法:每连接独立下行队列(256 帧 / 16MiB)和发送 goroutine。`PublishDown` 只入队;发送与上行读循环解耦。队列满返回 `ErrBackpressure`。
|
||||
- 原因:同连接同步 `InjectPacket` 与读循环写 PUBACK 会互相等待。
|
||||
- 备选方案:改 `PublishDown` 签名或继续用 20ms sleep。
|
||||
- 影响:调用方入队即返回;慢客户端只挡住该连接的发送 goroutine。
|
||||
|
||||
### 复审修复 B-06
|
||||
|
||||
- 日期:2026-09-30
|
||||
- 原条款:Gitea #13。`PublishDown` 校验当前连接与下行订阅;导出有效载荷上限。
|
||||
- 实际做法:非空 `connID` 必须仍是当前连接。未订阅 down 返回 `ErrNotSubscribed`。导出 `EffectivePayloadLimit`(Maximum Packet Size 减 128 字节包头预留)。`uplink.publishResp` 改用该函数。新连接建立时把旧连接标为 `superseded`。
|
||||
- 原因:旧连接或未订阅时写入会静默失败或写错连接。
|
||||
- 备选方案:发送时再检查(入队后连接可能已换)。
|
||||
- 影响:无订阅时下行立即失败,不再占用大帧名额。
|
||||
|
||||
### 复审修复 B-04
|
||||
|
||||
- 日期:2026-09-30
|
||||
- 原条款:Gitea #11。写出后再断开,不用固定 sleep。`serve.go` 只改 `identity.New` 的 ConnControl。
|
||||
- 实际做法:`PublishThenDisconnect` 把帧与断开原因一并入队,发送 goroutine 写完再 `Disconnect`。logout / fatalKick 改走该原语。`identity.New` 的 `ConnControl` 置 nil,踢线仍走 Session 钩子。
|
||||
- 原因:固定 20ms/50ms sleep 在慢客户端上会先断开,在快路径上又多余等待。
|
||||
- 备选方案:继续 sleep;或改 identity 生命周期(本线不改)。
|
||||
- 影响:identity 未接 ConnControl 时不再自己 20ms 踢线,生产路径统一由 Session 写出后断开。
|
||||
|
||||
### 复审修复 B-09
|
||||
|
||||
- 日期:2026-09-30
|
||||
- 原条款:Gitea #16。生命周期串行化。不改 presence/app.go。
|
||||
- 实际做法:broker 与 `appUplink` 按端编号加锁串行 `OnSessionEstablished` / `OnDisconnect` / 握手。uplink 另记 hello 握手表,仅已握手连接的断开才按当前连接通知消息线。
|
||||
- 原因:顶号时旧连接 `OnDisconnect` 可能和新连接登记交错。
|
||||
- 备选方案:改 presence 在线表(超出本线允许文件)。
|
||||
- 影响:未 hello 的断开不再把消息连接表当成已握手在线来清推送标记。
|
||||
|
||||
### 复审修复 B-10
|
||||
|
||||
- 日期:2026-09-30
|
||||
- 原条款:Gitea #17。登录写库条件更新;hello 重读令牌。不改 identity/self.go。
|
||||
- 实际做法:密码登录 `UPDATE ... WHERE COALESCE(session_hash,'') = 读到的旧值`,影响行数为 0 则 `ErrSessionWriteConflict`。hello 用 `TokenMatchesDB` 核对明文,库已被换则响应里不带回旧令牌。
|
||||
- 原因:两处同时密码登录会互相覆盖;hello 可能把已作废明文交给客户端。
|
||||
- 备选方案:写库后无条件返回本次签发明文。
|
||||
- 影响:写冲突时 OnConnect 返回 error(不回 0x86),客户端按网络故障重连。
|
||||
|
||||
### 复审修复 B-11
|
||||
|
||||
- 日期:2026-09-30
|
||||
- 原条款:Gitea #18。令牌闲置按在线计。
|
||||
- 实际做法:闲置判断取 `session_used_at` / `online_since` / `offline_since` 的较新者;当前在线(`online_since >= offline_since`)视为未闲置。
|
||||
- 原因:只看 `session_used_at` 会让长期在线却很少写库的令牌过期。
|
||||
- 备选方案:在线时每小时强制刷新 used_at(已有 touch,但仍可能窗口不够)。
|
||||
- 影响:在线设备不会因为闲置天数被踢;离线后从最后一次在线/离线时刻起算。
|
||||
|
||||
### 复审修复 B-12
|
||||
|
||||
- 日期:2026-09-30
|
||||
- 原条款:Gitea #19。认证超时与每端校验并发。不改 auth 池/PHC。
|
||||
- 实际做法:`Authenticate` 套 30 秒超时;argon2 `Verify` 前每端信号量 2。`OnConnect` 同样带 30 秒 ctx。
|
||||
- 原因:慢哈希或卡住的校验会堵住 mochi 读循环;同一编号并发登录会打满全局哈希池。
|
||||
- 备选方案:改全局 Pool 大小(超出允许文件)。
|
||||
- 影响:超时表现为内部错误断开(不回 0x86)。
|
||||
|
||||
### 复审修复 B-08
|
||||
|
||||
- 日期:2026-09-30
|
||||
- 原条款:Gitea #15。Shutdown API。完整 HTTP 停机依赖 L-03。
|
||||
- 实际做法:`Broker.Shutdown` 对现有连接发 MQTT 5 `0x8B`,清空上行队列并 `Close`。`serve` 在 listener Close 之前调用。HTTP `Shutdown` 留给 L-03。
|
||||
- 原因:只关 listener 时 MQTT 客户端看不到规范的停机原因码。
|
||||
- 备选方案:等 L-03 一并做(本线仍提供 broker API,避免监听线无法调用)。
|
||||
- 影响:进程退出时端会收到 server shutting down;监听器 HTTP 优雅停机仍未做。
|
||||
|
||||
Reference in New Issue
Block a user