feat: update inference reporting and ffmpeg video merge
This commit is contained in:
@@ -0,0 +1,241 @@
|
||||
# 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` 已基于修复后的代码构建完成,可用于后续部署验证。
|
||||
Reference in New Issue
Block a user