fix new-vm detection interval
All checks were successful
continuous-integration/drone/push Build is passing

This commit is contained in:
2026-01-21 09:36:19 +11:00
parent fd9cc185ce
commit 00805513c9
2 changed files with 61 additions and 27 deletions

View File

@@ -4,6 +4,7 @@ import (
"context"
"database/sql"
"fmt"
"strconv"
"strings"
"time"
@@ -43,18 +44,47 @@ func boolStringFromInterface(value interface{}) string {
// latestHourlySnapshotBefore finds the most recent hourly snapshot table prior to the given time, skipping empty tables.
func latestHourlySnapshotBefore(ctx context.Context, dbConn *sqlx.DB, cutoff time.Time) (string, error) {
rows, err := dbConn.QueryxContext(ctx, `
SELECT table_name, snapshot_time, snapshot_count
FROM snapshot_registry
WHERE snapshot_type = 'hourly' AND snapshot_time < ? AND snapshot_count > 0
ORDER BY snapshot_time DESC
LIMIT 50
`, cutoff.Unix())
tables, err := listLatestHourlyWithRows(ctx, dbConn, "", cutoff.Unix(), 1)
if err != nil {
return "", err
}
if len(tables) == 0 {
return "", nil
}
return tables[0].Table, nil
}
// parseSnapshotTime extracts the unix suffix from an inventory_hourly table name.
func parseSnapshotTime(table string) (int64, bool) {
const prefix = "inventory_hourly_"
if !strings.HasPrefix(table, prefix) {
return 0, false
}
ts, err := strconv.ParseInt(strings.TrimPrefix(table, prefix), 10, 64)
if err != nil {
return 0, false
}
return ts, true
}
// listLatestHourlyWithRows returns recent hourly snapshot tables (ordered desc by time) that have rows, optionally filtered by vcenter.
func listLatestHourlyWithRows(ctx context.Context, dbConn *sqlx.DB, vcenter string, beforeUnix int64, limit int) ([]snapshotTable, error) {
if limit <= 0 {
limit = 50
}
rows, err := dbConn.QueryxContext(ctx, `
SELECT table_name, snapshot_time, snapshot_count
FROM snapshot_registry
WHERE snapshot_type = 'hourly' AND snapshot_time < ?
ORDER BY snapshot_time DESC
LIMIT ?
`, beforeUnix, limit)
if err != nil {
return nil, err
}
defer rows.Close()
var out []snapshotTable
for rows.Next() {
var name string
var ts int64
@@ -65,23 +95,34 @@ LIMIT 50
if err := db.ValidateTableName(name); err != nil {
continue
}
// Rely on snapshot_count to avoid costly table scans; fall back to a cheap row check only if count is zero.
if count > 0 {
return name, nil
// Use snapshot_count first; fall back to row check (and vcenter filter) only when needed.
if count == 0 {
if has, _ := db.TableHasRows(ctx, dbConn, name); !has {
continue
}
}
if hasRows, _ := db.TableHasRows(ctx, dbConn, name); hasRows {
return name, nil
if vcenter != "" {
vrows, qerr := querySnapshotRows(ctx, dbConn, name, []string{"VmId"}, `"Vcenter" = ? LIMIT 1`, vcenter)
if qerr != nil {
continue
}
hasVcenter := vrows.Next()
vrows.Close()
if !hasVcenter {
continue
}
}
out = append(out, snapshotTable{Table: name, Time: ts})
}
return "", nil
return out, nil
}
// HasSnapshotGap reports whether the gap between prev and curr exceeds 2x the expected interval.
func HasSnapshotGap(prevUnix, currUnix int64, expectedSeconds int64) bool {
// SnapshotTooSoon reports whether the gap between prev and curr is significantly shorter than expected (default: <50% interval).
func SnapshotTooSoon(prevUnix, currUnix int64, expectedSeconds int64) bool {
if prevUnix == 0 || currUnix == 0 || expectedSeconds <= 0 {
return false
}
return currUnix-prevUnix > expectedSeconds*2
return currUnix-prevUnix < expectedSeconds/2
}
// querySnapshotRows builds a SELECT with proper rebind for the given table/columns/where.