提交 460aa4e5 authored 作者: 陈泽健's avatar 陈泽健

fix(服务自检): MQTT 主题订阅与消息推送检测恒失败修复

根因:订阅判定用 -match 'Connected'/'Subscribed',但 mosquitto_sub 从不输出这些文本,导致 7 个业务主题恒 0/7 失败;工具包架构硬编码 mqtt_test_x86;缺可执行性预检;推送判定靠文本匹配无端到端闭环。

修复:
- SSH uname -m 探测 → 自动选 mqtt_test_arm / mqtt_test_x86
- 上传后 ./mqtt version 预检,工具不可执行时明确报错并跳过
- 订阅判定改为以真实错误信号为失败基准(超时无消息=通道正常)
- 推送改为后台 sub -C 1 -v → pub → 校验订阅日志含测试消息

同步产出问题处理 + 计划执行双文档,更新 HANDOFF。Parser err=0、UTF-8 BOM、桌面字节级一致。
Co-Authored-By: 's avatarClaude <noreply@anthropic.com>
上级 8757a7c1
......@@ -204,6 +204,7 @@ function Test-MQTTConnection {
Write-Log -Level "INFO" -Message "[MQTT] ========== MQTT主题订阅检测 =========="
$topicSubResults = @()
$subscribedTopics = 0
$channelOkTopics = 0
$publishedTopics = 0
$mqttTopics = @(
"/androidPanel/",
......@@ -215,10 +216,21 @@ function Test-MQTTConnection {
"/iot/v1/device/service/request/"
)
# 上传 mqtt_test_x86 工具到远程服务器
# 上传 MQTT 测试工具到远程服务器
Write-Log -Level "INFO" -Message "[MQTT] 准备上传 MQTT 测试工具到远程服务器..."
$mqttToolDir = "/tmp/mqtt_test"
# 检测远程服务器架构,选择匹配架构的工具包(ARM 服务器需用 mqtt_test_arm)
$archCheckCmd = "uname -m"
$archResult = Invoke-SSHCommand -HostName $Server.IP -User $Server.User -Pass $Server.Pass -Port $Server.Port -Command $archCheckCmd
$remoteArch = ($archResult.Output -join "").Trim()
if ($remoteArch -match 'arm|aarch64') {
$mqttToolSrc = "mqtt_test_arm"
Write-Log -Level "INFO" -Message "[MQTT] 检测到 ARM 架构 ($remoteArch),使用 $mqttToolSrc"
} else {
$mqttToolSrc = "mqtt_test_x86"
Write-Log -Level "INFO" -Message "[MQTT] 检测到 x86 架构 ($remoteArch),使用 $mqttToolSrc"
}
# 创建远程工具目录
$createDirCmd = "mkdir -p $mqttToolDir 2>/dev/null || true"
......@@ -232,6 +244,7 @@ function Test-MQTTConnection {
# 检查本地工具是否存在
$mqttToolExists = Test-Path $localMqttToolPath
$mqttToolRunnable = $false # 工具是否可在远程服务器上执行
if ($mqttToolExists) {
Write-Log -Level "INFO" -Message "[MQTT] 本地 MQTT 工具路径: $localMqttToolPath"
......@@ -273,42 +286,75 @@ function Test-MQTTConnection {
}
Write-Log -Level "SUCCESS" -Message "[MQTT] MQTT 测试工具上传完成"
# 版本预检:执行 ./mqtt version 验证工具可执行性
# 失败时(架构不符/缺库)输出会包含 cannot execute / error while loading shared libraries / No such file
$versionCmd = "cd '$mqttToolDir' && export LD_LIBRARY_PATH='$mqttToolDir/lib':`$LD_LIBRARY_PATH' && ./mqtt version 2>&1 || echo 'MQTT_TOOL_VERSION_FAIL'"
$versionResult = Invoke-SSHCommand -HostName $Server.IP -User $Server.User -Pass $Server.Pass -Port $Server.Port -Command $versionCmd
$versionOutput = ($versionResult.Output -join " ").Trim()
if ($versionResult.ExitCode -eq 0 -and $versionOutput -notmatch 'MQTT_TOOL_VERSION_FAIL' -and $versionOutput -notmatch 'cannot execute' -and $versionOutput -notmatch 'No such file' -and $versionOutput -notmatch 'error while loading shared libraries') {
$mqttToolRunnable = $true
Write-Log -Level "SUCCESS" -Message "[MQTT] 工具版本预检通过: $versionOutput"
} else {
$mqttToolRunnable = $false
Write-Log -Level "ERROR" -Message "[MQTT] 工具不可执行(架构不符/缺库): $versionOutput"
Write-Log -Level "WARN" -Message "[MQTT] 跳过主题订阅与消息推送检测"
}
} else {
Write-Log -Level "WARN" -Message "[MQTT] 本地 MQTT 测试工具不存在: $localMqttToolPath"
Write-Log -Level "INFO" -Message "[MQTT] 跳过主题订阅检测"
}
# 执行主题订阅检测
if ($mqttToolExists) {
if ($mqttToolExists -and $mqttToolRunnable) {
$subscribedTopics = 0
$channelOkTopics = 0
foreach ($topic in $mqttTopics) {
# 订阅主题(在后台运行5秒后退出
# 设置 LD_LIBRARY_PATH 以确保 mqtt 工具能找到依赖库
$subCmd = "cd '$mqttToolDir' && export LD_LIBRARY_PATH='$mqttToolDir/lib':`$LD_LIBRARY_PATH' && timeout 5 ./mqtt sub -h localhost -t '$topic' -v 2>&1 || echo 'TIMEOUT'"
# 订阅主题(最多 5 秒):mosquitto_sub 只在收到消息时输出(-v 加 topic
# 它不输出 Connected/Subscribed,因此必须以"是否有连接错误"为失败判定基准
$subCmd = "cd '$mqttToolDir' && export LD_LIBRARY_PATH='$mqttToolDir/lib':`$LD_LIBRARY_PATH' && timeout 5 ./mqtt sub -h localhost -t '$topic' -v 2>&1 || echo 'MQTT_SUB_TIMEOUT'"
$subResult = Invoke-SSHCommand -HostName $Server.IP -User $Server.User -Pass $Server.Pass -Port $Server.Port -Command $subCmd
# 检查订阅是否成功(查找 "Connected" 或成功订阅的标志)
if ($subResult.Output -and ($subResult.Output -match 'Connected' -or $subResult.Output -match 'Subscribed')) {
$subOutput = ($subResult.Output -join " ").Trim()
# 失败判定:仅当出现真实错误信号时才判失败
# 注意:超时无消息(仅 MQTT_SUB_TIMEOUT 标记)不算失败,属于"订阅通道正常"
$isSubError = ($subOutput -match 'Connection refused') -or `
($subOutput -match 'Connection error') -or `
($subOutput -match 'cannot execute') -or `
($subOutput -match 'No such file') -or `
($subOutput -match 'error while loading shared libraries')
if ($isSubError) {
Write-Log -Level "WARN" -Message "[MQTT] 主题订阅失败: $topic (原始输出: $subOutput)"
$topicSubResults += @{
Topic = $topic
Status = "订阅失败"
Success = $false
}
} elseif ($subOutput -and $subOutput -notmatch 'MQTT_SUB_TIMEOUT') {
# 收到消息(有内容且非超时标记)→ 订阅成功
$subscribedTopics++
Write-Log -Level "SUCCESS" -Message "[MQTT] 主题订阅成功: $topic"
Write-Log -Level "SUCCESS" -Message "[MQTT] 主题订阅成功(已收到消息): $topic"
$topicSubResults += @{
Topic = $topic
Status = "订阅成功"
Success = $true
}
} else {
Write-Log -Level "WARN" -Message "[MQTT] 主题订阅失败或超时: $topic"
# 超时但无连接错误 → 订阅通道正常,无消息推送(不算失败)
$channelOkTopics++
Write-Log -Level "INFO" -Message "[MQTT] 主题订阅通道正常(无消息推送): $topic"
$topicSubResults += @{
Topic = $topic
Status = "订阅失败"
Success = $false
Status = "通道正常"
Success = $true
}
}
}
Write-Log -Level "INFO" -Message "[MQTT] 主题订阅完成: 成功 $subscribedTopics/$($mqttTopics.Count) 个"
Write-Log -Level "INFO" -Message "[MQTT] 主题订阅完成: 成功 $subscribedTopics/$($mqttTopics.Count), 通道正常 $channelOkTopics/$($mqttTopics.Count) 个, 失败 $(($topicSubResults | Where-Object { -not $_.Success }).Count)/$($mqttTopics.Count)"
# 方法E:MQTT消息推送检测
# 方法E:MQTT消息推送检测(端到端闭环:后台订阅 + 发布 + 校验收到测试消息)
Write-Log -Level "INFO" -Message "[MQTT] ========== MQTT消息推送检测 =========="
$topicPubResults = @()
$publishedTopics = 0
......@@ -320,15 +366,36 @@ function Test-MQTTConnection {
Write-Log -Level "INFO" -Message "[MQTT] 测试推送主题: $testTopic"
Write-Log -Level "INFO" -Message "[MQTT] 测试消息内容: $testMessage"
# 端到端闭环:
# 1) 后台启动订阅(-C 1:收到 1 条后退出,-v:带 topic 输出),输出写入临时文件
# 2) sleep 2 让订阅端就绪
# 3) 发布测试消息
# 4) 校验 pub exit 0 且订阅文件包含测试消息
$subLogFile = "/tmp/mqtt_pub_test_sub.log"
$subBgCmd = "cd '$mqttToolDir' && export LD_LIBRARY_PATH='$mqttToolDir/lib':`$LD_LIBRARY_PATH' && (timeout 8 ./mqtt sub -h localhost -t '$testTopic' -C 1 -v > '$subLogFile' 2>&1 &) && sleep 2"
Invoke-SSHCommand -HostName $Server.IP -User $Server.User -Pass $Server.Pass -Port $Server.Port -Command $subBgCmd | Out-Null
# 发布测试消息
# 设置 LD_LIBRARY_PATH 以确保 mqtt 工具能找到依赖库
$pubCmd = "cd '$mqttToolDir' && export LD_LIBRARY_PATH='$mqttToolDir/lib':`$LD_LIBRARY_PATH' && ./mqtt pub -h localhost -t '$testTopic' -m '$testMessage' 2>&1"
$pubCmd = "cd '$mqttToolDir' && export LD_LIBRARY_PATH='$mqttToolDir/lib':`$LD_LIBRARY_PATH' && ./mqtt pub -h localhost -t '$testTopic' -m '$testMessage' 2>&1 || echo 'MQTT_PUB_FAIL'"
$pubResult = Invoke-SSHCommand -HostName $Server.IP -User $Server.User -Pass $Server.Pass -Port $Server.Port -Command $pubCmd
$pubOutput = ($pubResult.Output -join " ").Trim()
# 检查推送是否成功
if ($pubResult.ExitCode -eq 0 -or ($pubResult.Output -match 'sent successfully' -or $pubResult.Output -match 'Connection closed')) {
# 等待后台订阅端收完消息并退出
Start-Sleep -Seconds 3
# 读取后台订阅日志,校验是否真的收到测试消息
$readSubLogCmd = "cat '$subLogFile' 2>/dev/null || echo 'MQTT_SUB_LOG_MISSING'"
$subLogResult = Invoke-SSHCommand -HostName $Server.IP -User $Server.User -Pass $Server.Pass -Port $Server.Port -Command $readSubLogCmd
$subLogText = ($subLogResult.Output -join " ").Trim()
# 推送成功判定:pub exit 0 且订阅日志包含测试消息内容
$isPubOk = ($pubResult.ExitCode -eq 0) -and `
($pubOutput -notmatch 'MQTT_PUB_FAIL') -and `
($subLogText -match [regex]::Escape($testMessage))
if ($isPubOk) {
$publishedTopics++
Write-Log -Level "SUCCESS" -Message "[MQTT] 消息推送成功: $testTopic"
Write-Log -Level "SUCCESS" -Message "[MQTT] 消息推送成功(订阅端已收到): $testTopic"
$topicPubResults += @{
Topic = $testTopic
Message = $testMessage
......@@ -336,7 +403,8 @@ function Test-MQTTConnection {
Success = $true
}
} else {
Write-Log -Level "WARN" -Message "[MQTT] 消息推送失败: $testTopic"
$pubErrDetail = "pub exit=$($pubResult.ExitCode), pub输出: $pubOutput, 订阅日志: $subLogText"
Write-Log -Level "WARN" -Message "[MQTT] 消息推送失败: $testTopic ($pubErrDetail)"
$topicPubResults += @{
Topic = $testTopic
Message = $testMessage
......@@ -345,14 +413,24 @@ function Test-MQTTConnection {
}
}
# 清理临时订阅日志
$rmSubLogCmd = "rm -f '$subLogFile' 2>/dev/null || true"
Invoke-SSHCommand -HostName $Server.IP -User $Server.User -Pass $Server.Pass -Port $Server.Port -Command $rmSubLogCmd | Out-Null
Write-Log -Level "INFO" -Message "[MQTT] 消息推送检测完成"
}
# 汇总结果
if ($mqttToolExists) {
$detailMsg += " | 主题订阅: $subscribedTopics/$($mqttTopics.Count) 成功"
if ($mqttToolRunnable) {
$detailMsg += " | 主题订阅: 成功 $subscribedTopics/$($mqttTopics.Count), 通道正常 $channelOkTopics/$($mqttTopics.Count)"
if ($publishedTopics -gt 0) {
$detailMsg += " | 消息推送: 成功"
} else {
$detailMsg += " | 消息推送: 失败"
}
} else {
$detailMsg += " | 主题订阅/消息推送: 跳过(工具不可执行)"
}
} else {
$detailMsg += " | 主题订阅: 跳过(工具不存在)"
......
......@@ -2,7 +2,7 @@
> **生成时间**:2026-08-25
> **会话主题**:服务自检脚本自动修复全面禁用 + 模块导入作用域修复 + 加载警告抑制
> **最近更新**:2026-09-01(资源检测日志乱码修复闭环 commit `2c4596ea`;本会话 develop 未提交内容分组提交推送 5 次 `646bdbaf..baa815f5` + 服务自检代码桌面 md5 复核一致)
> **最近更新**:2026-09-01(资源检测日志乱码修复闭环 commit `2c4596ea`;本会话 develop 未提交内容分组提交推送 5 次 `646bdbaf..baa815f5` + 服务自检代码桌面 md5 复核一致;MQTT 主题订阅与消息推送检测异常修复 + 双文档
---
......@@ -55,6 +55,10 @@
| 32 | 资源检测日志乱码 - 计划执行文档 | `Docs/PRD/服务自检/问题修复/_PRD_资源检测日志乱码_问题处理_计划执行.md` | 2026-09-01 创建:执行步骤全 [x]、已修复内容表、附录关键代码位置(行号级修复前后对照);commit `2c4596ea` 已推送 |
| 33 | 【本次会话】develop 未提交内容分组提交推送 | develop 分支 `da2fa1d9` / `e8774f05` / `8a91d8c5` / `1e8018f7` / `baa815f5` | 本会话(2026-09-01)用户确认"全部提交仅排除 temp"后,按逻辑分组 5 次提交推送 `646bdbaf..baa815f5`:①集群部署方案 07-11 六文档(含 stash 恢复的概览 +15 行、changelog v1.1)②达梦核对报告 V2 + 2 个 txt ③Tengine VIP 部署脚本/文档(arm/x86)+ onlyoffice ④ujava2 死锁问题处理 + fastdfs 分析报告 ⑤达梦数据库 DM8 部署与 dmp 导入脚本(含 dmp 数据文件)。全程逐文件/逐目录 add(遵守警示 #4);`AuxiliaryTool/FunctionalTestReportGeneration/temp/` 运行产物按用户选择不提交不删除,留工作区 |
| 34 | 【本次会话】服务自检代码桌面副本复核 | `C:\Users\29194\Desktop\Sever_health_check\` | 2026-09-01 手工核对:`check_server_health.ps1` / `.sh` / `_auto.sh` 桌面与仓库 md5 完全一致(桌面时间戳 08-31 18:51 为上次同步记录,仓库今天 checkout),服务自检代码桌面副本=仓库最新版;桌面目录结构(lib/modules/plink 等)同步 |
| 35 | 【本次会话】MQTT 主题订阅与消息推送检测异常 - 问题处理文档 | `Docs/PRD/服务自检/问题修复/_PRD_MQTT主题订阅与消息推送检测异常_问题处理.md` | 2026-09-01 创建:定位 4 个根因(订阅判定条件与 mosquitto_sub 实际输出不符 - 主因 / 工具包架构硬编码 / 缺可执行性预检 / 推送判定文本匹配不可靠无闭环) |
| 36 | 【本次会话】MQTT 主题订阅与消息推送检测异常 - 计划执行文档 | `Docs/PRD/服务自检/问题修复/_PRD_MQTT主题订阅与消息推送检测异常_问题处理_计划执行.md` | 2026-09-01 创建:步骤全 [x]、修复详情(4 项修复代码段)、验证结果(Parser 0 errors / BOM / 桌面字节级一致)、测试计划 |
| 37 | 【本次会话】MQTT 检测代码修复 | `modules/MiddlewareCheck.psm1` 方法D/方法E(约 203-410 行) | ①架构自动选择:SSH `uname -m``mqtt_test_arm`/`mqtt_test_x86`(对齐 FastDFS 先例)②上传后 `./mqtt version` 预检,不可执行时明确报错并跳过 ③订阅判定修正:真实错误信号(Connection refused/cannot execute/缺库)才判失败,超时无消息=通道正常,收到消息=成功 ④推送端到端闭环:后台 sub `-C 1 -v` → pub → 校验订阅日志含测试消息 |
| 38 | 【本次会话】MQTT 修复桌面同步 + 语法验证 | `C:\Users\29194\Desktop\Sever_health_check\modules\MiddlewareCheck.psm1` | 旧版备份 `.bak_YYYYMMDDHHMMSS``cp` + `cmp -s` 字节级一致;PowerShell Parser err=0;UTF-8 BOM=True;80153 bytes |
### 验证结果
......@@ -133,6 +137,23 @@ ServerResourceAnalysis.psm1: err=0 DNSCheck.psm1: err=0 MiddlewareCheck.
ServerResourceAnalysis.psm1 第 8/9/10/11 节中文已对齐 sh 版 check_server_health.sh 与 Report.psm1(#region / Write-Log 消息 / 状态串 / 注释)
```
### 【2026-09-01 MQTT 主题订阅与消息推送检测异常修复】验证结果
```
# PowerShell 解析器语法校验(PS 5.1 powershell.exe)
MiddlewareCheck.psm1: err=0
# 字节级 / BOM 校验
文件大小: 80153 bytes UTF-8 BOM: True
# 桌面同步
cp + cmp -s: 字节级一致(MiddlewareCheck.psm1)
# 旧版备份:modules/MiddlewareCheck.psm1.bak_YYYYMMDDHHMMSS
# 4 项修复点
① 架构自动选择(uname -m → mqtt_test_arm / mqtt_test_x86)
② 上传后 ./mqtt version 预检(不可执行时明确报错 + 跳过)
③ 订阅判定:Connection refused/cannot execute/No such file/缺库 才判失败;超时无消息 = 通道正常(INFO);收到消息 = 订阅成功
④ 推送端到端闭环:后台 sub -C 1 -v → pub → 校验订阅日志含测试消息
```
---
## 当前阻塞项
......@@ -155,6 +176,8 @@ ServerResourceAnalysis.psm1 第 8/9/10/11 节中文已对齐 sh 版 check_server
**2026-09-01 本会话(develop 未提交内容收尾)**:用户确认"全部提交仅排除 temp"后,按逻辑分组 5 次提交推送 `646bdbaf..baa815f5`(集群部署方案 07-11、达梦核对报告、Tengine VIP、ujava2/fastdfs 问题处理、达梦 DM8 部署与 dmp 导入),全程逐文件 add;temp/ 运行产物留工作区不提交。另复核服务自检代码桌面副本 md5 与仓库一致。无新增阻塞。
**2026-09-01 MQTT 主题订阅与消息推送检测异常修复**:定位 4 个根因并修复(见表格 #35-38):订阅判定条件与 mosquitto_sub 实际输出不符(主因,`-match 'Connected'/'Subscribed'` 恒假 → 恒 0/7 失败)、工具包架构硬编码 x86、缺可执行性预检、推送判定无端到端闭环。代码 + 问题处理/计划执行双文档产出,Parser err=0、BOM 校验通过、桌面字节级同步一致。待实际环境测试 + 提交推送。
---
## 下一步计划
......@@ -173,6 +196,7 @@ ServerResourceAnalysis.psm1 第 8/9/10/11 节中文已对齐 sh 版 check_server
| 10 | 【2026-09-01】资源检测日志乱码修复闭环(代码 + 双文档 + HANDOFF) | ✅ 已完成:ServerResourceAnalysis.psm1 24 处 + DNSCheck.psm1 1 处重建,Parser err=0,审计清零,问题处理+计划执行双文档产出;commit `2c4596ea` 已推送 develop |
| 11 | 【2026-09-01】本会话 develop 未提交内容分组提交推送 | ✅ 已完成:用户确认"全部提交仅排除 temp",5 次提交推送 `646bdbaf..baa815f5`(集群部署 07-11 / 达梦核对报告 / Tengine VIP / ujava2+fastdfs / 达梦 DM8+dmp);temp/ 运行产物留工作区不提交 |
| 12 | 【2026-09-01】服务自检代码桌面副本复核 | ✅ 已完成:`check_server_health.ps1` / `.sh` / `_auto.sh` 桌面与仓库 md5 一致,服务自检代码桌面=仓库最新版 |
| 13 | 【2026-09-01】MQTT 主题订阅与消息推送检测异常修复(代码 + 双文档 + 桌面同步) | ✅ 已完成:4 个根因(订阅判定条件不符 / 架构硬编码 / 缺预检 / 推送无闭环)均已修复,MiddlewareCheck.psm1 Parser err=0、BOM=True、桌面字节级一致;问题处理 + 计划执行双文档已产出。**待实际环境测试 + 提交推送** |
---
......@@ -188,6 +212,7 @@ ServerResourceAnalysis.psm1 第 8/9/10/11 节中文已对齐 sh 版 check_server
8.**桌面同步必须覆盖 modules/ 全部模块与 lib/,不能只同步主脚本** — 2026-09-01 复核发现上次只同步了 sh/auto/ps1/ServiceCheck.psm1 四个脚本,**漏了 7 个文件**(ConfigIPCheck/DataBackup/FilePermission/LogExport/Report/ShellAdapter.psm1 + `lib/shell/config_check.sh`),桌面长时间停留在旧版。同步后务必对整个 `ServiceSelfInspection\` 目录执行 `diff -rq` 全量校验,确认 0 差异才算完成。
9. ❌ **方案/需求类 md 文档不要同步到桌面测试目录** — 2026-09-01 曾误将 `PowerShell模块修复项确认改进方案.md`、`修复项确认交互改进方案.md` 拷入桌面后按用户要求删除。桌面目录 `C:\Users\29194\Desktop\Sever_health_check\` 只放运行脚本 + 模块 + lib;md 文档仅保留在仓库 Docs 中。全量 diff 校验时这两类文件属预期差异,不算漏同步。
10.**中文乱码"烘焙"进源码文件 = 有损不可逆,只能手工重建** — 2026-09-01 资源检测日志乱码:UTF-8 中文被误按 GBK 解码后**以乱码形式写回文件**(仍是合法 UTF-8,编辑器不报编码错,所以"改终端编码/换编码查看"都无效)。含 U+FFFD 替换字符时字节级自动复原有损,必须按行号手工重建正确中文。**改码铁律**:任何批量"转码/改编码"操作前后用字节级校验(BOM + 严格 UTF-8 + GBK/UTF-8 双编码检索关键中文),确认目标中文确实可检索到,防止"转了个寂寞"。PS 模块中文文案新增/修改后同样校验。
11.**mosquitto_sub / mosquitto_pub 成功时是静默的(不输出 Connected/Subscribed)** — 2026-09-01 MQTT 检测失败教训:原判定条件 `-match 'Connected' -or -match 'Subscribed'` 必然不成立,导致 7 个业务主题恒 0/7 失败。**判定条件必须以"真实错误信号"(Connection refused / cannot execute / 缺库)为失败基准**,而不是"成功标志"——因为成功对这些工具而言是无输出。`mosquitto_pub` 成功时 exit 0 且无输出,文本匹配(`sent successfully`/`Connection closed`)不可靠;正确做法是端到端闭环(后台订阅 -C 1 -v → 发布 → 校验订阅日志含测试消息)。
---
......@@ -208,6 +233,8 @@ ServerResourceAnalysis.psm1 第 8/9/10/11 节中文已对齐 sh 版 check_server
| 取消预设选择计划执行文档 | `Docs/PRD/服务自检/新需求/_PRD_服务自检_取消预设服务器选择默认手动输入_计划执行.md` | 2026-08-31 创建,已实施,交互/回归测试全部 ✅ 已验证 |
| 资源检测日志乱码 - 问题处理文档 | `Docs/PRD/服务自检/问题修复/_PRD_资源检测日志乱码_问题处理.md` | 2026-09-01 创建:根因(源码烘焙乱码)+ 字节级证据 + 修复对照表 + 预防措施 |
| 资源检测日志乱码 - 计划执行文档 | `Docs/PRD/服务自检/问题修复/_PRD_资源检测日志乱码_问题处理_计划执行.md` | 2026-09-01 创建:执行步骤全 [x] + 行号级修复前后对照表 |
| MQTT 主题订阅与消息推送检测异常 - 问题处理文档 | `Docs/PRD/服务自检/问题修复/_PRD_MQTT主题订阅与消息推送检测异常_问题处理.md` | 2026-09-01 创建:4 个根因(订阅判定 / 架构硬编码 / 缺预检 / 推送无闭环)+ 解决分析 |
| MQTT 主题订阅与消息推送检测异常 - 计划执行文档 | `Docs/PRD/服务自检/问题修复/_PRD_MQTT主题订阅与消息推送检测异常_问题处理_计划执行.md` | 2026-09-01 创建:步骤全 [x] + 修复详情 5 段 + 验证结果 + 测试计划 |
| 桌面测试目录 | `C:\Users\29194\Desktop\Sever_health_check\` | **用户实际运行环境**(注意:不是 `Desktop\Test\`) |
| 相关提交 | `2c4596ea`(资源检测日志乱码修复 + 双文档)/ `71bbf9c3`(HANDOFF 会话闭环详情)/ `9d111845`(统一平台分类路径细分代码 11 文件)/ `9be5c892`(HANDOFF 细分闭环)/ `d8a2ef45` / `9896ecc0` / `dd7b3bc5` / `87f96484` / `1bdf43f4` / `1e9acc44` | develop 分支,均已推送 |
......@@ -243,4 +270,12 @@ ServerResourceAnalysis.psm1 第 8/9/10/11 节中文已对齐 sh 版 check_server
> - 文档:问题处理 + 计划执行双文档产出(`Docs/PRD/服务自检/问题修复/`)
> - 提交推送:commit `2c4596ea` 已推送 develop 分支(5 files, 309+/27-)
>
> **2026-09-01 MQTT 主题订阅与消息推送检测异常修复**:
>
> - 根因 4 项:①订阅判定 `-match 'Connected'/'Subscribed'` 与 mosquitto_sub 实际输出不符(成功是静默的,条件恒假 → 7 主题恒 0/7 失败)②工具包架构硬编码 `mqtt_test_x86`(ARM 服务器二进制无法执行)③上传后无可执行性预检(执行失败被误判为业务失败)④推送判定靠文本匹配(`sent successfully`/`Connection closed`)无端到端闭环
> - 修复 4 项:①SSH `uname -m` 探测 → 选 `mqtt_test_arm`/`mqtt_test_x86`(对齐 FastDFS `Test-FastDFSConnection:1001-1006` 先例)②上传后 `./mqtt version` 预检,工具不可执行时给出明确原因(架构不符/缺库)并跳过检测 ③订阅判定:以"真实错误信号"(Connection refused/cannot execute/缺库)为失败基准;超时无消息 = 订阅通道正常(INFO,不计入失败);收到消息 = 订阅成功 ④推送端到端闭环:后台 `sub -C 1 -v > file` → sleep 2 → `pub -m` → 校验 pub exit 0 **且** 订阅文件含测试消息内容
> - 验证:Parser err=0、UTF-8 BOM=True、桌面 `cp + cmp -s` 字节级一致、80153 bytes
> - 文档:问题处理 + 计划执行双文档(`Docs/PRD/服务自检/问题修复/`),含 4 段修复代码、路径计算对比表、测试计划与回归测试清单
> - 提交:待用户确认后逐文件 add + commit 推送(develop 分支)
>
> 后续如需继续服务自检相关工作,先 `Read` 本交接文档与本目录下的 PRD 问题处理文档;磁盘上的桌面测试目录是用户实际验证环境(`C:\Users\29194\Desktop\Sever_health_check\`),改代码务必同步两处。
\ No newline at end of file
# _PRD_MQTT主题订阅与消息推送检测异常_问题处理
> 来源:
- `AuxiliaryTool\ScriptTool\ServiceSelfInspection\modules\MiddlewareCheck.psm1`
- `AuxiliaryTool/ScriptTool/ServiceSelfInspection/check_server_health.sh`(参考实现)
## 1. 背景与目标
### 1.1 背景
执行服务自检主脚本后,MQTT 测试工具上传成功,但 7 个业务主题**全部订阅失败(成功 0/7 个)**,消息推送检测也**一直失败**。该问题在多次执行中反复出现,从未成功过。
### 1.2 目标
修复 MQTT 主题订阅检测与消息推送检测的成功判定逻辑,确保:
- 主题订阅检测能正确识别"订阅成功 / 通道正常无消息 / 订阅失败"三种状态;
- 消息推送检测能正确验证消息端到端送达;
- 支持 ARM / x86 双架构服务器;
- 工具包不可执行时给出明确诊断信息而非误报失败。
---
## 2. 问题报错信息
### 2.1 问题一:主题订阅恒失败(成功 0/7)
```ignorelang
[2026-09-01 16:19:07] [INFO] [MQTT] 准备上传 MQTT 测试工具到远程服务器...
[2026-09-01 16:19:07] [SUCCESS] [MQTT] MQTT 测试工具上传完成
[2026-09-01 16:19:08] [INFO] [MQTT] ========== MQTT主题订阅检测 ==========
[2026-09-01 16:19:08] [WARN] [MQTT] 主题订阅失败或超时: /androidPanel/
[2026-09-01 16:19:08] [WARN] [MQTT] 主题订阅失败或超时: /iot/v1/conference/service/request/
[2026-09-01 16:19:08] [WARN] [MQTT] 主题订阅失败或超时: message/paperLessService/callService
[2026-09-01 16:19:08] [WARN] [MQTT] 主题订阅失败或超时: message/paperLessAuthor/onthewall
[2026-09-01 16:19:08] [WARN] [MQTT] 主题订阅失败或超时: /meeting/message/
[2026-09-01 16:19:08] [WARN] [MQTT] 主题订阅失败或超时: /iot/v1/device/event/request/
[2026-09-01 16:19:08] [WARN] [MQTT] 主题订阅失败或超时: /iot/v1/device/service/request/
[2026-09-01 16:19:08] [INFO] [MQTT] 主题订阅完成: 成功 0/7 个
```
### 2.2 问题二:消息推送恒失败
```ignorelang
[2026-09-01 16:19:08] [INFO] [MQTT] ========== MQTT消息推送检测 ==========
[2026-09-01 16:19:08] [INFO] [MQTT] 测试推送主题: /androidPanel/
[2026-09-01 16:19:08] [INFO] [MQTT] 测试消息内容: test_message_from_health_check_20260901161907
[2026-09-01 16:19:13] [WARN] [MQTT] 消息推送失败: /androidPanel/
```
### 2.3 关键线索
- `MQTT 测试工具上传完成` 为 SUCCESS 级别——工具上传链路正常,问题出在**工具执行后的结果判定**
- 每次运行时,同一批次 7 个主题**全部**失败——不符合"个别主题无人订阅/无消息"的预期,更像是**判定条件恒不成立****工具根本未执行成功**
- 工具包分别耗时约 5 秒(订阅)与 5 秒(推送),与 `timeout 5``sleep` 组合吻合,说明命令确实执行到了超时路径。
---
## 3. 问题解决分析
### 3.1 根因一:订阅成功判定条件与 mosquitto_sub 实际输出不符(主因)
**问题代码位置:** `MiddlewareCheck.psm1` 原第 287-306 行(方法D 主题订阅检测)
```powershell
$subCmd = "cd '$mqttToolDir' && export LD_LIBRARY_PATH='$mqttToolDir/lib':`$LD_LIBRARY_PATH' && timeout 5 ./mqtt sub -h localhost -t '$topic' -v 2>&1 || echo 'TIMEOUT'"
$subResult = Invoke-SSHCommand ...
if ($subResult.Output -and ($subResult.Output -match 'Connected' -or $subResult.Output -match 'Subscribed')) {
... 订阅成功 ...
} else {
... 订阅失败 ...
}
```
**分析:**
1. `mosquitto_sub` 是命令行的 MQTT 订阅客户端,**只在收到消息时输出消息内容**`-v` 时格式为 `topic payload`);
2.**从不输出** `Connected` / `Subscribed` 这类文本(与 mosquitto_pub 类似,连接成功是静默的);
3. 被检测的 7 个业务主题平时**无消息推送**,5 秒超时后无任何输出;
4. 因此 `-match 'Connected' -or -match 'Subscribed'` 条件**必然不成立**,无论 broker 是否正常、订阅是否成功,结果恒为"订阅失败"→ `成功 0/7 个`
**结论:** 当前判定逻辑是"必然失败"逻辑,与工具实际行为不符。
### 3.2 根因二:工具包架构硬编码为 x86,ARM 服务器上二进制无法执行
**问题代码位置:** `MiddlewareCheck.psm1` 原第 220-221 行
```powershell
$mqttToolDir = "/tmp/mqtt_test"
$mqttToolSrc = "mqtt_test_x86" # 硬编码,无架构判断
```
**分析:**
1. 仓库同时提供了 `mqtt_test_x86/`(musl 链接)与 `mqtt_test_arm/`(glibc aarch64)两个工具包;
2. shell 版 `check_server_health.sh` 第 1911-1918 行已有架构探测逻辑:`uname -m` 匹配 `arm|aarch64` → 选 `mqtt_test_arm`,否则 `mqtt_test_x86`
3. `MiddlewareCheck.psm1` 硬编码 `mqtt_test_x86`,若目标服务器为 ARM,上传的二进制**因可执行格式不符无法运行**
4. 同模块 `Test-FastDFSConnection`(第 1001-1006 行)已有 `uname -m` + `arm|aarch64` 架构选择的成熟先例可复用。
### 3.3 根因三:缺少工具可执行性预检,执行失败被误判为业务失败
**分析:**
1. shell 版在执行订阅/推送前先做版本预检(`mosquitto_pub --version`),工具不可用则降级或明确提示;
2. ps1 版上传后**不做任何预检**,直接开始订阅/推送;
3. 若二进制无法执行(架构不符、缺依赖库、权限异常),输出会包含 `cannot execute` / `error while loading shared libraries` / `No such file` 等错误,但现有判定只看 `Connected`/`Subscribed`,看不到这些诊断信息,只能笼统报"订阅失败",**掩盖了真正原因**
### 3.4 根因四:消息推送判定依赖文本匹配,缺乏端到端闭环验证
**问题代码位置:** `MiddlewareCheck.psm1` 原第 325-346 行(方法E 消息推送检测)
```powershell
$pubCmd = "cd '$mqttToolDir' && export LD_LIBRARY_PATH='$mqttToolDir/lib':`$LD_LIBRARY_PATH' && ./mqtt pub -h localhost -t '$testTopic' -m '$testMessage' 2>&1"
if ($pubResult.ExitCode -eq 0 -or ($pubResult.Output -match 'sent successfully' -or $pubResult.Output -match 'Connection closed')) {
```
**分析:**
1. `mosquitto_pub` 成功发送时**静默退出**(exit 0),不输出 `sent successfully`;而 `Connection closed` 在连接异常时反而可能出现,作为成功标志不可靠;
2. 推送检测只验证"发出去了"(单向),未验证"订阅端真的收到了这条消息"(端到端);
3. shell 版采用"后台订阅 `-C 1 -v` → 发布 → 校验收到消息内容与测试消息一致"的闭环验证,ps1 版未实现。
---
## 4. 解决分析总结
| 根因 | 问题代码位置 | 严重度 | 影响 |
|------|--------------|--------|------|
| 订阅成功判定条件与工具输出不符(`Connected`/`Subscribed` 从不输出) | `MiddlewareCheck.psm1` 方法D | 🔴 高 | 7 个主题恒 0/7 失败 |
| 工具包架构硬编码 `mqtt_test_x86` | `MiddlewareCheck.psm1:220-221` | 🔴 高 | ARM 服务器工具无法执行 |
| 缺工具可执行性预检 | 上传后、订阅前 | 🟠 中 | 执行失败被误判为业务失败,掩盖根因 |
| 推送判定文本匹配不可靠、无端到端闭环验证 | `MiddlewareCheck.psm1` 方法E | 🟠 中 | 推送结果误判 |
### 规范文档
- 代码规范: `Docs/PRD/01规范文档/_PRD_规范文档_代码规范.md`
- 问题总结: `Docs/PRD/01规范文档/_PRD_问题总结_记录文档.md`
- 方法总结: `Docs/PRD/01规范文档/_PRD_方法总结_记录文档.md`
- 文档规范: `Docs/PRD/01规范文档/_PRD_规范文档_文档规范.md`
- 测试规范: `Docs/PRD/01规范文档/_PRD_规范文档_测试规范.md`
---
*文档结束*
\ No newline at end of file
# 计划执行文档 - MQTT主题订阅与消息推送检测异常问题处理
## 执行时间
- 创建时间:2026-09-01
- 更新时间:2026-09-01
- 执行状态:进行中
---
## 问题概述
执行服务自检主脚本后 MQTT 测试工具上传成功,但 7 个业务主题全部订阅失败(成功 0/7 个),消息推送检测也一直失败,多次执行从未成功过。
**错误信息:**
```ignorelang
[2026-09-01 16:19:08] [WARN] [MQTT] 主题订阅失败或超时: /androidPanel/
[2026-09-01 16:19:08] [WARN] [MQTT] 主题订阅失败或超时: /iot/v1/conference/service/request/
...
[2026-09-01 16:19:08] [INFO] [MQTT] 主题订阅完成: 成功 0/7 个
[2026-09-01 16:19:13] [WARN] [MQTT] 消息推送失败: /androidPanel/
```
**问题分析(4 个根因):**
- 根因一(主因):订阅成功判定用 `-match 'Connected' -or -match 'Subscribed'`,但 `mosquitto_sub` 从不输出这些文本 → 判定条件必然不成立 → 恒 0/7 失败
- 根因二:工具包架构硬编码 `mqtt_test_x86`,ARM 服务器上二进制无法执行
- 根因三:上传后无工具可执行性预检,执行失败被误判为业务失败
- 根因四:推送判定依赖文本匹配(`sent successfully`/`Connection closed`),不可靠且无端到端闭环验证
---
## 执行步骤
### 步骤 1:问题定位
- [x] 读取问题处理文档(`_PRD_MQTT主题订阅与消息推送检测异常_问题处理.md`
- [x] 分析失败日志,确认每次都是 7/7 全失败、推送失败
- [x] 定位问题代码:MiddlewareCheck.psm1 方法D(主题订阅,约 203-309 行)与方法E(消息推送,约 311-348 行)
- [x] 对比 shell 版 `check_server_health.sh` 的健壮实现(架构选择、版本预检、订阅判定、端到端消息验证)
### 步骤 2:根因分析
**根因一:订阅成功判定条件与 mosquitto_sub 实际输出不符(主因)**
- `mosquitto_sub` 只输出收到的消息内容(`-v` 时为 `topic payload`),**从不输出** `Connected`/`Subscribed`
- 7 个业务主题平时无消息推送 → 5 秒超时无输出 → `-match` 必然不成立 → 恒判失败
- 这正是"成功 0/7 个"且从未成功过的直接原因
**根因二:工具包架构硬编码 x86**
- `$mqttToolSrc = "mqtt_test_x86"` 无架构判断
- 仓库同时提供 `mqtt_test_x86/`(musl)与 `mqtt_test_arm/`(glibc aarch64)
- shell 版已有 `uname -m``arm|aarch64` 选择逻辑;同模块 `Test-FastDFSConnection`(1001-1006 行)也有先例
**根因三:缺可执行性预检**
- `mosquitto_pub --version` / `mosquitto_sub --version` 可快速验证二进制能否运行
- 无预检时 `cannot execute``error while loading shared libraries` 等真实错误被笼统报为"订阅失败"
**根因四:推送判定脆弱、无闭环**
- `mosquitto_pub` 成功时静默 exit 0,不输出 `sent successfully`
- `Connection closed` 在异常时反而可能出现,作为成功标志不可靠
- 缺少"后台订阅 → 发布 → 校验收到消息内容一致"的端到端验证(shell 版已实现)
### 步骤 3:解决方案
**方案要点(对齐 shell 版行为):**
1. **架构检测**:SSH 执行 `uname -m`,匹配 `arm|aarch64``mqtt_test_arm`,否则 `mqtt_test_x86`
2. **版本预检**:上传后执行 `./mqtt version`(即 mosquitto_sub --version)验证可执行性,失败则明确记录工具不可用原因并跳过检测(不误报业务失败)
3. **订阅判定修正**
- 输出含 `Connection refused` / `Connection error` / `cannot execute` / `No such file` / `error while loading shared libraries` → 判"订阅失败",并记录原始输出便于诊断
- 超时(5 秒无消息)但无连接错误 → 判"订阅通道正常(无消息推送)"(INFO,**不计入失败**
- 收到消息(有输出且非错误)→ 判"订阅成功"(计数)
4. **推送判定修正(端到端闭环)**
- 后台 `timeout 5 ./mqtt sub -t $testTopic -C 1 -v` 写入临时文件
- `sleep 2``./mqtt pub -t $testTopic -m $testMessage`
- 校验 pub exit 0 **且** 订阅文件内容包含测试消息 → "推送成功";否则失败并记录原始输出
5. **汇总信息**`主题订阅: X/N 成功 | 消息推送: 成功/失败`
### 步骤 4:修复执行
- [x] 修改 `MiddlewareCheck.psm1` 方法D/方法E 逻辑(架构检测、版本预检、判定修正、闭环推送)
- [x] PowerShell 语法验证(Parser 错误数 = 0)
- [x] 按 UTF-8 with BOM 写回(模块文件 BOM 铁律)
- [x] 同步桌面测试目录并字节级 diff 校验
- [ ] 更新 HANDOFF 会话交接文档(与本次修复同步)
---
## 执行结果
### 已修改文件
| 文件 | 修改位置 | 修改内容 | 状态 |
|------|----------|----------|------|
| MiddlewareCheck.psm1 | 方法D/方法E(MQTT检测,约 203-410 行) | 架构检测 + 版本预检 + 订阅/推送判定修正 + 端到端闭环推送 | ✅ 已修复 |
| _PRD_MQTT主题订阅与消息推送检测异常_问题处理.md | 新增 | 问题背景、根因、报错信息、解决分析 | ✅ 已建档 |
| _PRD_MQTT主题订阅与消息推送检测异常_问题处理_计划执行.md | 新增 | 执行步骤、修复详情、测试计划 | ✅ 已建档 |
### 修复详情
**修复 1:架构自动选择(解决根因二)**
```powershell
# 检测远程服务器架构,选择匹配架构的工具包(ARM 服务器需用 mqtt_test_arm)
$archCheckCmd = "uname -m"
$archResult = Invoke-SSHCommand -HostName $Server.IP -User $Server.User -Pass $Server.Pass -Port $Server.Port -Command $archCheckCmd
$remoteArch = ($archResult.Output -join "").Trim()
if ($remoteArch -match 'arm|aarch64') {
$mqttToolSrc = "mqtt_test_arm"
Write-Log -Level "INFO" -Message "[MQTT] 检测到 ARM 架构 ($remoteArch),使用 $mqttToolSrc"
} else {
$mqttToolSrc = "mqtt_test_x86"
Write-Log -Level "INFO" -Message "[MQTT] 检测到 x86 架构 ($remoteArch),使用 $mqttToolSrc"
}
```
**修复 2:版本预检,工具不可执行时跳过(解决根因三)**
```powershell
$versionCmd = "cd '$mqttToolDir' && export LD_LIBRARY_PATH='$mqttToolDir/lib':`$LD_LIBRARY_PATH' && ./mqtt version 2>&1 || echo 'MQTT_TOOL_VERSION_FAIL'"
$versionResult = Invoke-SSHCommand ...
$versionOutput = ($versionResult.Output -join " ").Trim()
if (... 成功标志 ...) {
$mqttToolRunnable = $true
Write-Log -Level "SUCCESS" -Message "[MQTT] 工具版本预检通过: $versionOutput"
} else {
$mqttToolRunnable = $false
Write-Log -Level "ERROR" -Message "[MQTT] 工具不可执行(架构不符/缺库): $versionOutput"
Write-Log -Level "WARN" -Message "[MQTT] 跳过主题订阅与消息推送检测"
}
```
**修复 3:订阅成功判定修正(解决根因一)**
```powershell
# 失败判定:仅当出现真实错误信号时才判失败
# 注意:超时无消息(仅 MQTT_SUB_TIMEOUT 标记)不算失败,属于"订阅通道正常"
$isSubError = ($subOutput -match 'Connection refused') -or `
($subOutput -match 'Connection error') -or `
($subOutput -match 'cannot execute') -or `
($subOutput -match 'No such file') -or `
($subOutput -match 'error while loading shared libraries')
if ($isSubError) {
# 失败:记录原始输出便于诊断
... 订阅失败 ...
} elseif ($subOutput -and $subOutput -notmatch 'MQTT_SUB_TIMEOUT') {
# 收到消息 → 订阅成功
$subscribedTopics++
... 订阅成功 ...
} else {
# 超时无消息 + 无连接错误 → 订阅通道正常(不计入失败)
$channelOkTopics++
... 通道正常 ...
}
```
**修复 4:消息推送端到端闭环验证(解决根因四)**
```powershell
# 1) 后台启动订阅(-C 1:收到 1 条后退出,-v:带 topic 输出),输出写入临时文件
# 2) sleep 2 让订阅端就绪
# 3) 发布测试消息
# 4) 校验 pub exit 0 且订阅文件包含测试消息
$subLogFile = "/tmp/mqtt_pub_test_sub.log"
$subBgCmd = "cd '$mqttToolDir' && ... (timeout 8 ./mqtt sub -h localhost -t '$testTopic' -C 1 -v > '$subLogFile' 2>&1 &) && sleep 2"
Invoke-SSHCommand ... $subBgCmd | Out-Null
$pubCmd = "cd '$mqttToolDir' && ... ./mqtt pub -h localhost -t '$testTopic' -m '$testMessage' 2>&1 || echo 'MQTT_PUB_FAIL'"
$pubResult = Invoke-SSHCommand ... $pubCmd
Start-Sleep -Seconds 3
$readSubLogCmd = "cat '$subLogFile' 2>/dev/null || echo 'MQTT_SUB_LOG_MISSING'"
$subLogResult = Invoke-SSHCommand ... $readSubLogCmd
$subLogText = ($subLogResult.Output -join " ").Trim()
# 推送成功判定:pub exit 0 且订阅日志包含测试消息内容
$isPubOk = ($pubResult.ExitCode -eq 0) -and `
($pubOutput -notmatch 'MQTT_PUB_FAIL') -and `
($subLogText -match [regex]::Escape($testMessage))
```
**修复 5:汇总信息更新**
```powershell
if ($mqttToolExists) {
if ($mqttToolRunnable) {
$detailMsg += " | 主题订阅: 成功 $subscribedTopics/$($mqttTopics.Count), 通道正常 $channelOkTopics/$($mqttTopics.Count)"
$detailMsg += if ($publishedTopics -gt 0) { " | 消息推送: 成功" } else { " | 消息推送: 失败" }
} else {
$detailMsg += " | 主题订阅/消息推送: 跳过(工具不可执行)"
}
} else {
$detailMsg += " | 主题订阅: 跳过(工具不存在)"
}
```
### 路径计算对比
| 步骤 | 修复前 | 修复后 |
|------|--------|--------|
| 工具包选择 | 硬编码 `mqtt_test_x86` | `uname -m``mqtt_test_arm` / `mqtt_test_x86` |
| 工具可执行性 | 上传后直接订阅/推送,无预检 | `./mqtt version` 预检,失败明确报错 |
| 订阅成功判定 | `-match 'Connected' -or -match 'Subscribed'`(恒假) | 真实错误信号(Connection refused / cannot execute 等)才判失败;超时无消息 = 通道正常;收到消息 = 成功 |
| 推送成功判定 | 文本匹配(`sent successfully` / `Connection closed`) | 端到端闭环:pub exit 0 **且** 订阅端日志含测试消息内容 |
### 验证结果
| 项目 | 命令 | 结果 |
|------|------|------|
| PowerShell 语法 | `[Parser]::ParseFile(...)` | ✅ 0 errors |
| UTF-8 BOM | `[IO.File]::ReadAllBytes(...)` | ✅ True |
| 桌面同步 | `cmp -s` 字节级 | ✅ SYNC_OK |
| 模块大小 | 80153 bytes | ✅ 正常 |
### 桌面同步
- 源文件:`E:\github\ubains-module-test\develop\AuxiliaryTool\ScriptTool\ServiceSelfInspection\modules\MiddlewareCheck.psm1`
- 目标:`C:\Users\29194\Desktop\Sever_health_check\modules\MiddlewareCheck.psm1`
- 同步方式:直接 `cp` + `cmp -s` 字节级校验
- 旧版备份:`MiddlewareCheck.psm1.bak_YYYYMMDDHHMMSS`
---
## 附录:关键代码位置
| 项目 | 位置 | 说明 |
|------|------|------|
| 根因一(原代码,已替换) | `MiddlewareCheck.psm1:291` | `-match 'Connected' -or -match 'Subscribed'` 必然不成立 |
| 根因二(原代码,已替换) | `MiddlewareCheck.psm1:221` | 硬编码 `$mqttToolSrc = "mqtt_test_x86"` |
| 根因三(原代码,已替换) | `MiddlewareCheck.psm1:236-279` | 上传后无 `--version` 预检 |
| 根因四(原代码,已替换) | `MiddlewareCheck.psm1:325-346` | 推送判定靠文本匹配,无闭环验证 |
| 参照实现 | `check_server_health.sh:1888-2227` | 架构选择/版本预检/订阅判定/端到端消息验证 |
| 架构先例 | `MiddlewareCheck.psm1:1001-1006` | FastDFS `uname -m``arm|aarch64` 选择脚本 |
### mosquitto_sub / mosquitto_pub 行为说明
| 行为 | mosquitto_sub | mosquitto_pub |
|------|---------------|---------------|
| 连接成功 | 无输出 | 无输出,exit 0 |
| 收到消息 | 输出 `topic payload``-v`) | - |
| 无消息超时 | 无输出(被 timeout 杀掉) | - |
| 连接失败 | `Connection refused` / `Connection error` | `Connection refused`,非 0 |
| 二进制不可执行 | `cannot execute` / `No such file` | `error while loading shared libraries` |
### 模块开发最佳实践(本次修复验证)
在模块中调用便携二进制工具时:
1. 先做架构检测:`uname -m` 选择匹配架构的工具包,避免上传后无法执行
2. 上传后立即用 `--version` 做可执行性预检,把"工具问题"与"业务问题"区分开
3. 判定条件必须与工具**实际输出行为**一致(mosquitto 系列工具成功是静默的)
4. 关键链路做端到端闭环验证(推送 → 收到消息内容一致),而不是只看发送端退出码
---
## 问题状态
| 状态 | 说明 |
|------|------|
| 问题类型 | MQTT 检测结果误判(成功判定逻辑错误 + 架构硬编码) |
| 根本原因 | 判定条件与工具实际行为不符;工具包架构硬编码;缺预检与闭环验证 |
| 影响范围 | MQTT 主题订阅检测、消息推送检测 |
| 当前状态 | ✅ 已修复 |
| 修复日期 | 2026-09-01 |
| 验证状态 | 待实际环境测试 |
### 测试计划
**测试环境:**
- 需要可访问的 EMQX 服务器(容器方式部署)
- 主脚本目录下有 `mqtt_test_x86``mqtt_test_arm` 工具包
**测试步骤:**
1. 执行主脚本 `.\check_server_health.ps1`(PowerShell 模式)
2. 确认 MQTT 检测根据服务器架构自动选择工具包
3. 确认订阅检测不再全量误报失败(无消息主题应为"通道正常"而非"失败")
4. 确认消息推送检测端到端成功(订阅端确实收到测试消息)
5. 在 ARM 服务器上用 arm 工具包重复验证
**预期结果:**
- [ ] 日志显示正确架构的工具包路径(`mqtt_test_x86``mqtt_test_arm`
- [ ] 订阅检测:业务主题显示"订阅通道正常"或"订阅成功",**不再出现 0/7 全失败**
- [ ] 消息推送:`消息推送成功: /androidPanel/`
- [ ] 若工具不可执行:日志给出明确原因(如 `cannot execute` / 缺库),而非笼统"失败"
### 回归测试
- [ ] 既有 MQTT 相关检测(方法A/B/C:Dashboard API/TCP/进程)不受影响
- [ ] 服务自检脚本其他模块(Redis/MySQL/FastDFS)不受影响
---
## 规范文档
- 代码规范: `Docs/PRD/01规范文档/_PRD_规范文档_代码规范.md`
- 问题总结: `Docs/PRD/01规范文档/_PRD_问题总结_记录文档.md`
- 方法总结: `Docs/PRD/01规范文档/_PRD_方法总结_记录文档.md`
- 文档规范: `Docs/PRD/01规范文档/_PRD_规范文档_文档规范.md`
- 测试规范: `Docs/PRD/01规范文档/_PRD_规范文档_测试规范.md`
---
*文档结束*
\ No newline at end of file
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论