mirror of
https://github.com/MeshCore-Beacon/beacon-server.git
synced 2026-09-05 03:33:48 +00:00
@@ -0,0 +1,19 @@
|
||||
-- Copyright 2026 Beacon Contributors
|
||||
-- SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
-- Cleans up observer_telemetry rows written from /status messages whose
|
||||
-- "stats" object was missing or renamed. status.go's json.Unmarshal
|
||||
-- silently tolerated the missing object, leaving the stats struct at Go
|
||||
-- zero-values, and the row was inserted unconditionally from there --
|
||||
-- uptime_secs=0, battery_mv=0, noise_floor=0, tx/rx_air_secs=0. With the
|
||||
-- hourly ON CONFLICT (observer_id, reported_at) DO NOTHING dedup,
|
||||
-- whichever message landed first per hour won, so these zero rows
|
||||
-- regularly became the hour's telemetry and corrupted the 24h/7d/30d
|
||||
-- aggregates (AVG(noise_floor_db), AVG(battery_voltage_mv), MAX-MIN
|
||||
-- airtime).
|
||||
--
|
||||
-- Safe because a running observer never reports uptime_seconds == 0;
|
||||
-- this is the same signal now used by status.go to skip the insert going
|
||||
-- forward (see internal/ingest/status.go handleStatus).
|
||||
|
||||
DELETE FROM observer_telemetry WHERE uptime_seconds = 0;
|
||||
+31
-26
@@ -96,7 +96,12 @@ func (w *Worker) handleStatus(ctx context.Context, pubkeyHex string, raw []byte)
|
||||
StatusMetadata: raw,
|
||||
LastStatusAt: time.Now(),
|
||||
}
|
||||
params.UptimeSeconds = &envelope.Stats.UptimeSeconds
|
||||
// A running observer never reports 0, so treat this the same as a missing
|
||||
// stats object and leave the existing value alone (COALESCE in the SQL)
|
||||
// rather than stomping it with a zero.
|
||||
if envelope.Stats.UptimeSeconds != 0 {
|
||||
params.UptimeSeconds = &envelope.Stats.UptimeSeconds
|
||||
}
|
||||
if envelope.Stats.BatteryMV != 0 {
|
||||
batteryLevel := float32(envelope.Stats.BatteryMV) / 1000
|
||||
params.BatteryLevel = &batteryLevel
|
||||
@@ -151,32 +156,32 @@ func (w *Worker) handleStatus(ctx context.Context, pubkeyHex string, raw []byte)
|
||||
return
|
||||
}
|
||||
// Store a telemetry snapshot at the configured resolution.
|
||||
resolution := w.cfg.TelemetryResolution
|
||||
if resolution == 0 {
|
||||
resolution = time.Hour
|
||||
}
|
||||
reportedAt := time.Now().Truncate(resolution)
|
||||
batteryMV := int32(envelope.Stats.BatteryMV)
|
||||
txAirSecs := float32(envelope.Stats.TxAirSecs)
|
||||
rxAirSecs := float32(envelope.Stats.RxAirSecs)
|
||||
queueLen := int32(envelope.Stats.QueueLen)
|
||||
debugFlags := int32(envelope.Stats.DebugFlags)
|
||||
recvErrors := int32(envelope.Stats.RecvErrors)
|
||||
// A running observer never reports uptime_secs == 0, so its absence (or a
|
||||
// missing/renamed "stats" object entirely) means this payload has no usable
|
||||
// stats — skip the insert rather than writing an all-zero row that would win
|
||||
// the hourly dedup and pollute the telemetry aggregates.
|
||||
if envelope.Stats.UptimeSeconds == 0 {
|
||||
log.Printf("ingest[%s]: status from %s has no usable stats (uptime_secs missing or zero), skipping telemetry insert", w.cfg.BrokerName, pubkeyHex)
|
||||
} else {
|
||||
resolution := w.cfg.TelemetryResolution
|
||||
if resolution == 0 {
|
||||
resolution = time.Hour
|
||||
}
|
||||
reportedAt := time.Now().Truncate(resolution)
|
||||
batteryMV := int32(envelope.Stats.BatteryMV)
|
||||
txAirSecs := float32(envelope.Stats.TxAirSecs)
|
||||
rxAirSecs := float32(envelope.Stats.RxAirSecs)
|
||||
queueLen := int32(envelope.Stats.QueueLen)
|
||||
debugFlags := int32(envelope.Stats.DebugFlags)
|
||||
recvErrors := int32(envelope.Stats.RecvErrors)
|
||||
|
||||
if err := w.db.InsertObserverTelemetry(
|
||||
ctx,
|
||||
observerID,
|
||||
reportedAt,
|
||||
&batteryMV,
|
||||
&txAirSecs,
|
||||
&rxAirSecs,
|
||||
envelope.Stats.NoiseFloor,
|
||||
envelope.Stats.UptimeSeconds,
|
||||
&queueLen,
|
||||
&debugFlags,
|
||||
&recvErrors,
|
||||
); err != nil {
|
||||
log.Printf("ingest[%s]: db: insert telemetry failed for %s: %v", w.cfg.BrokerName, pubkeyHex, err)
|
||||
if err := w.db.InsertObserverTelemetry(
|
||||
ctx, observerID, reportedAt, &batteryMV, &txAirSecs, &rxAirSecs,
|
||||
envelope.Stats.NoiseFloor, envelope.Stats.UptimeSeconds,
|
||||
&queueLen, &debugFlags, &recvErrors,
|
||||
); err != nil {
|
||||
log.Printf("ingest[%s]: db: insert telemetry failed for %s: %v", w.cfg.BrokerName, pubkeyHex, err)
|
||||
}
|
||||
}
|
||||
|
||||
iata, err := w.db.GetObserverLastIATA(ctx, observerID)
|
||||
|
||||
Reference in New Issue
Block a user