Skip to content

[Bug] telemetry_writer fallbackInsert 函数因 historyData 与 currentData 长度不一致导致 index out of range 崩溃 #268

Description

@Li-ChenZhong

问题描述

thingspanel-backend-community/internal/storage/telemetry_writer.gofallbackInsert 函数发生 panic:

panic: runtime error: index out of range [8] with length 8
goroutine 43 [running]:
project/internal/storage.(*telemetryWriter).fallbackInsert.func1(...)
	...telemetry_writer.go:328
...

根本原因

历史数据表和历史最新值表的去重规则不同:

切片 去重键 同一批次条数
historyData(历史表) device_id + key + ts 全部保留(如 3帧×8个指标 = 24条
currentData(最新值表) device_id + key 每个指标只留最新(如 8条

deduplicateAndConvert(第195-253行)返回的两个切片,当一个 flush 批次内包含同一设备的多个时间戳时,长度天然不一致

fallbackInsert同一个下标 i 同时索引两个切片:

for i := range historyData {
    ...
    .Create(&historyData[i]).Error   // 正常
    .Create(&currentData[i]).Error   // 当 i >= len(currentData) 时越界 panic
}

len(historyData) > len(currentData) 时,currentData[i] 越界崩溃。

触发条件

  1. 批量插入失败,降级为逐条插入(进入 fallbackInsert
  2. 一个 flush 批次内包含同一设备的多个时间戳(高频设备上报)

我们的场景:传感器每 0.1 秒上报一次,每帧 8 个遥测点。批量插入失败且跨批次时必现崩溃。

影响

  • 后端遥测写入 goroutine 崩溃
  • 遥测数据可能丢失
  • 影响所有设备的遥测入库

修复建议

将历史表和最新值表的插入拆成两个独立循环,各自遍历自己的切片:

// 历史表单独循环
for i := range historyData {
    // tx.Create(&historyData[i])
}

// 最新值表单独循环
for i := range currentData {
    // tx.Create(&currentData[i])
}

环境

  • thingspanel-backend-community
  • GORM v1.25.7
  • Go 1.22
  • TimescaleDB 14

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions