FireLeave_tool/docs/2026-07-05_fix_and_build_changelog.md

242 lines
8.4 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.

# 2026-07-05 修改日志
本文记录本次代码审查后实际落地的修复、影响范围、验证结果和构建产物。
## 1. 本次目标
修复代码审查中确认的 1、2、4、5、8 号问题,并重新构建新的程序到 `bin/fireleave_tool`
涉及的问题包括:
- `fire_check` 报警上传/上报失败时仍被当作成功处理
- 心跳超时重启会扩大影响,可能同时重启两个推理进程
- 视频时间戳解析和合并异常处理不可靠
- WebSocket 重连可能并发启动多个重连循环
- `copyFile` 超时返回后后台 goroutine 仍可能继续写文件
## 2. 修改文件
主要修改:
- `main.go`
- `connect/heartbeat.go`
- `connect/ws_channel.go`
- `reporter/reporter.go`
- `video_server/video_merge.go`
- `bin/fireleave_tool`
构建/环境相关:
- 本机安装了 Go 编译器
- 当前构建使用 `go1.26.4`
- 新二进制目标为 `linux/arm64`
## 3. 详细修改内容
### 3.1 `fire_check` 上报成功语义修复
原问题:
`fire_check` 报警触发后,上传视频和 WebSocket 上报在异步流程中执行。调用方无法知道最终是否真正上传成功、是否真正写入 WebSocket因此主流程可能提前清理 `FireCheckCandidate` 状态。这样会造成“报警没有报上去,但本地状态认为已经处理完成”的风险。
修改后:
- `reporter.UploadVideoAndReportFireCheck()` 改为同步执行。
- 视频上传失败会返回 error。
- WebSocket 未初始化或未连接会返回 error。
- 事件上报失败会返回 error。
- 数据快照上报失败会返回 error。
- 只有视频上传、事件上报、快照上报都成功后才清理合并文件并返回成功。
- `reporter.TriggerFireCheckAlarm()` 改为返回 `bool`
- `true` 表示报警已完整处理成功
- `false` 表示合并、上传、上报或并发锁获取失败
- `main.go` 中只有当 `TriggerFireCheckAlarm()` 返回 `true` 时才清空 `FireCheckCandidate``FireCheckFirstSeen``FireCheckLastSeen`
影响:
- `fire_check` 报警处理会比原来更严格,调用路径会等待上传和 WebSocket 写入完成。
- 如果平台或网络异常,本地候选状态不会被误清理,后续仍有机会重新触发。
- 失败场景下日志可能增加,但这是为了避免报警丢失。
### 3.2 `fire_check` 连续检测状态修复
原问题:
旧逻辑在收到推理结果的分支中立即判断持续时间并触发上报。如果上报失败,状态仍可能被重置。同时检测结果和上报处理耦合较重。
修改后:
- `deviceAlarmState` 中使用:
- `FireCheckCandidate`
- `FireCheckFirstSeen`
- `FireCheckLastSeen`
- 收到火焰推理结果时只更新候选状态和最近一次看到火焰的时间。
-`monitorTicker` 分支中统一判断是否达到 `fire_check` 持续时间。
- 增加 `fireCheckLastSeenGrace`,避免检测帧之间的短暂间隔导致候选状态过早失效。
影响:
- 火焰检测持续时间判断更稳定。
- 上报是否成功会影响候选状态是否清理。
- 短暂丢帧不一定立即打断候选状态。
### 3.3 心跳重启范围修复
原问题:
`fire_leave``fire_check` 某一个推理进程心跳超时时,旧逻辑会调用共享重启流程,可能把两个推理进程都重启。这样会扩大影响面,也可能造成重复重启。
修改后:
- 新增 `connect.RestartInferenceProcess(deviceData, processUUID)`
- 该函数只重启指定的 `processUUID`
- 主模型:`deviceUUID`
- 火焰模型:`deviceUUID_fire_check`
- `connect.StartInferenceProcess()` 保留兼容行为,仍可重启两路推理。
- `main.go` 心跳监控改为:
- `fire_leave` 超时只重启 `deviceUUID`
- `fire_check` 超时只重启 `deviceUUID_fire_check`
- 重启后只刷新对应进程的心跳时间。
影响:
- 单路推理异常不会连带影响另一路推理。
- 保留旧的 `StartInferenceProcess()`,避免已有调用点失效。
- 重启逻辑仍使用 `connect.GlobalPortManager` 获取原端口。
### 3.4 视频合并异常处理修复
原问题:
`video_server.parseSimpleTimestamp()` 直接按固定下标切片,遇到异常文件名可能 panic。`MergeVideo()` 虽然有 recover但旧逻辑存在 panic 后没有明确错误返回的风险。
修改后:
- `MergeVideo()` 改为命名返回值:
- `mergedPath string`
- `err error`
- `recover` 捕获 panic 后会设置:
- `mergedPath = ""`
- `err = fmt.Errorf("merge video panic: %v", recovered)`
- `parseSimpleTimestamp()` 增加文件名长度校验。
- 年、月、日、时、分、秒解析失败时都会返回明确 error。
- `getTimestampFromPath()` 改为返回 `(int64, error)`
- 排序和时间戳匹配逻辑会处理解析失败,必要时回退到文件名排序。
影响:
- 异常文件名不会导致程序崩溃。
- 视频合并失败会更明确地返回错误,调用方可感知失败。
- 正常命名的 mp4 文件处理逻辑不变。
### 3.5 WebSocket 重连并发修复
原问题:
读循环、心跳循环、发送失败都可能触发 `reconnect()`。如果多个错误同时发生,可能启动多个重连 goroutine并在重连成功后重复启动心跳循环。
修改后:
- `WSClient` 增加 `reconnecting bool`
- 新增:
- `startReconnect()`
- `startReconnectLocked()`
- 所有触发重连的地方都通过 `startReconnect` 系列方法进入。
- 同一时间只允许一个重连循环运行。
- 重连完成后重置 `reconnecting`
- 重连成功后只恢复 `readLoop()`,不再重复启动新的 `heartbeatLoop()`
- 重新订阅时先复制 `subscribers` map再遍历订阅降低并发读写风险。
- `RegisterService()``SubscribeTopic()` 使用本地 `client := GetWSClient()`,减少直接访问全局变量的竞态窗口。
影响:
- 断线时重连行为更可控。
- 减少 goroutine 堆积和重复 heartbeat 的风险。
- WebSocket 正常收发路径不变。
### 3.6 `copyFile` 超时写入修复
原问题:
`copyFile` 使用 goroutine 执行复制,外层通过 context 超时返回。超时后后台 goroutine 仍可能继续写目标文件,导致函数已经失败但文件仍在被写入,甚至留下半成品。
修改后:
- `copyFile` 改为同步分块复制。
- 每次循环检查 30 秒 deadline。
- 读取和写入使用 1MB buffer。
- 超时、读失败、写失败、短写或 sync 失败时都会删除目标文件。
- 函数返回后不再有后台 goroutine 继续写文件。
影响:
- 超时后不会继续写目标文件。
- 失败时不保留不完整目标文件。
- 大文件复制仍可能耗时,但行为更确定。
## 4. 构建与验证
已执行:
```text
gofmt -w main.go connect/heartbeat.go connect/ws_channel.go reporter/reporter.go video_server/video_merge.go
go test ./...
go build -o bin/fireleave_tool.new .
```
验证结果:
```text
go test ./... 通过
所有包均为 [no test files]
```
新构建产物:
```text
bin/fireleave_tool
```
构建信息:
```text
go version: go1.26.4
GOOS: linux
GOARCH: arm64
CGO_ENABLED: 0
binary size: 10011779 bytes
```
构建完成后已清理 `bin` 目录旧产物,当前 `bin` 目录只保留:
```text
bin/fireleave_tool
```
## 5. 兼容性与风险说明
### 保持兼容的部分
- `connect.StartInferenceProcess()` 保留,已有调用仍可使用。
- `fire_leave` 报警入口仍保持异步上报行为。
- WebSocket 消息结构和 topic 订阅逻辑没有改协议。
- 视频文件命名规则未改变。
### 行为变化
- `fire_check` 上报变为同步确认成功。
- `fire_check` 上报失败时不会清空候选报警状态。
- 心跳超时只重启异常的单个推理进程。
- WebSocket 同一时间只允许一个重连流程。
- 文件复制超时会删除不完整目标文件。
### 仍需关注
- 当前部分历史中文注释已经存在编码损坏,后续维护时建议逐步替换成清晰 UTF-8 注释。
- `reporter` 中仍有旧的 event cycle 相关逻辑,当前未完全重构,只做了本次问题相关的收敛。
- 如果现场网络长期异常,`fire_check` 候选状态可能持续重试,需要结合日志确认是否需要增加队列、退避或最大重试策略。
## 6. 本次结论
本次修复重点是避免误判成功、缩小重启影响、减少并发重连和后台写文件风险。新的 `bin/fireleave_tool` 已基于修复后的代码构建完成,可用于后续部署验证。