Files
MemRelay/projects/25464650-ed5d-440e-b362-190f2852d451/Checkpoint 2026-09-30 04-37-44 UTC [cea96f7c13].md
T
memrelay b73900b969 create: Checkpoint 2026-09-30 04:37:44 UTC [cea96f7c13]
MemRelay-Operation: checkpoint-save:issue3-rootcause-diag-20260930-1235
MemRelay-Resource: 7fd55d99-e2fa-4f59-b963-2b14d5e592b7
2026-09-30 12:37:47 +08:00

45 lines
3.0 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
title: Checkpoint 2026-09-30 04:37:44 UTC [cea96f7c13]
type: checkpoint
permalink: main/projects/25464650-ed5d-440e-b362-190f2852d451/checkpoint-2026-09-30-04-37-44-utc-cea96f7c13
stable_id: 7fd55d99-e2fa-4f59-b963-2b14d5e592b7
scope: project
memory_type: checkpoint
project_id: 25464650-ed5d-440e-b362-190f2852d451
usage_profile_id: 0c9feb46-d06e-43cd-9ef0-c5813c84a998
status: active
revision: 1
request_id: issue3-rootcause-diag-20260930-1235
created_at: '2026-09-30T04:37:44.082486+00:00'
updated_at: '2026-09-30T04:37:44.082486+00:00'
tags:
- issue-3
- diagnosis
---
# 检查点:issue #3 根因已实证(不是服务端死锁)
基线 main 4059a15。诊断工作树 E:\code\NixMsg-wt\diag3(分支 diag/issue3-scratch,仅本地,完成后删除)。
## 结论
TestUplinkDMOfflineGroupRecall 等"resp 回不来"是测试用 WebSocket 客户端 test/harness/mqtt.go 的两个缺陷,不是服务端死锁:
1. wsMQTT.Recv 把一个 WS 二进制帧当作恰好一个 MQTT 包;mochi 在 outbound 有积压时把多个包放进 outbuf 一次 Write,合成一个 WS 帧(MQTT5 §6 [MQTT-6.0.0-3] 允许)。客户端只解第一个包。实证日志:`WS frame carries 3 MQTT packets: [group_event group_event resp/rid=g1]` 随后 `timeout waiting resp rid=g1`。通过的轮次里也在丢 receipt/group_event。
2. wsMQTT.Send / writeWSClientFrame 帧头和载荷分两次 Write、无锁;读循环回 PUBACK 与测试线程发请求并发时交错,把发往服务端的 WS 流写乱,服务端卡在读一个错乱长度的包(无报错日志)。
## 对照实验(同步 emit,无 20ms sleep)
- 原客户端:6 次 1 失败(合帧含 resp)。
- 只修接收按字节流拆包:20 次 2 失败(g1、s4,无服务端报错)。
- 再修发送加锁+整帧一次写:20/20 通过(125 个合包帧正确拆开);cmd/nixmsg、test/accept、group、broker 全绿。
## 解决方向
- 修 test/harness/mqtt.go:Recv 按字节流缓冲拆包(含 continuation 帧);Send/PONG 加互斥锁并整帧一次 Write。
- 修好后删除 internal/app/group/app.go emit 的 goroutine+20ms sleep,改回同步下发。
- 不要合入 E:\code\NixMsg-wt\fix3 的 broker 改动(基于错误假设,改变 PUBACK 时序)。
- 更正 docs/DEVIATIONS.md 「死锁未修(issue #3)」与 Q accept-rest 第 3/4 条的错误结论。
## 另发现的真实隐患(待入 issue)
- mochi v2.7.9(最新版)inflight.go NextImmediate 先 RLock 再调 GetAll 又 RLock,递归读锁;server.go processPacket 719-728 在 sendQuota>0 且 inflight 非空时调用。客户端带 ReceiveMaximum(SDK 可能带)时,与 publishToClient 的 Inflight.Set 写锁排队可永久互等,卡死该连接读循环及所有向其下发的 goroutine(含 messageLoops)。测试客户端不带 ReceiveMaximum 所以没触发。
- identity lifecycle.go 有 kickFlushDelay=20ms sleep(fix #4 引入),待审。
## 下一步
全量审查 + 写 issue(含不冲突的解决方案与并行分组),交负责人审核后由 Grok 团队修。