Files
fire_leave_tool/docs/2026-07-05_fix_and_build_changelog.md
T

8.4 KiB
Raw Blame History

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 时才清空 FireCheckCandidateFireCheckFirstSeenFireCheckLastSeen

影响:

  • fire_check 报警处理会比原来更严格,调用路径会等待上传和 WebSocket 写入完成。
  • 如果平台或网络异常,本地候选状态不会被误清理,后续仍有机会重新触发。
  • 失败场景下日志可能增加,但这是为了避免报警丢失。

3.2 fire_check 连续检测状态修复

原问题:

旧逻辑在收到推理结果的分支中立即判断持续时间并触发上报。如果上报失败,状态仍可能被重置。同时检测结果和上报处理耦合较重。

修改后:

  • deviceAlarmState 中使用:
    • FireCheckCandidate
    • FireCheckFirstSeen
    • FireCheckLastSeen
  • 收到火焰推理结果时只更新候选状态和最近一次看到火焰的时间。
  • monitorTicker 分支中统一判断是否达到 fire_check 持续时间。
  • 增加 fireCheckLastSeenGrace,避免检测帧之间的短暂间隔导致候选状态过早失效。

影响:

  • 火焰检测持续时间判断更稳定。
  • 上报是否成功会影响候选状态是否清理。
  • 短暂丢帧不一定立即打断候选状态。

3.3 心跳重启范围修复

原问题:

fire_leavefire_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. 构建与验证

已执行:

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 .

验证结果:

go test ./... 通过
所有包均为 [no test files]

新构建产物:

bin/fireleave_tool

构建信息:

go version: go1.26.4
GOOS: linux
GOARCH: arm64
CGO_ENABLED: 0
binary size: 10011779 bytes

构建完成后已清理 bin 目录旧产物,当前 bin 目录只保留:

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 已基于修复后的代码构建完成,可用于后续部署验证。