fix new-vm detection interval
All checks were successful
continuous-integration/drone/push Build is passing
All checks were successful
continuous-integration/drone/push Build is passing
This commit is contained in:
@@ -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.
|
||||
|
||||
@@ -1104,23 +1104,16 @@ func (c *CronTask) compareWithPreviousSnapshot(
|
||||
c.Logger.Warn("failed to locate previous hourly snapshot for deletion comparison", "error", prevTableErr, "url", url)
|
||||
}
|
||||
|
||||
prevSnapshotTime := int64(0)
|
||||
if prevTableName != "" {
|
||||
if suffix := strings.TrimPrefix(prevTableName, "inventory_hourly_"); suffix != prevTableName {
|
||||
if ts, err := strconv.ParseInt(suffix, 10, 64); err == nil {
|
||||
prevSnapshotTime = ts
|
||||
}
|
||||
}
|
||||
}
|
||||
prevSnapshotTime, _ := parseSnapshotTime(prevTableName)
|
||||
|
||||
newCount := 0
|
||||
if prevTableName != "" {
|
||||
moreMissing := c.markMissingFromPrevious(ctx, dbConn, prevTableName, url, startTime, presentSnapshots, presentByUuid, presentByName, inventoryByVmID, inventoryByUuid, inventoryByName)
|
||||
missingCount += moreMissing
|
||||
expectedSeconds := int64(durationFromSeconds(c.Settings.Values.Settings.VcenterInventorySnapshotSeconds, time.Hour).Seconds())
|
||||
// Allow runs as soon as half the normal interval; treat larger gaps as unreliable for "new" detection.
|
||||
if HasSnapshotGap(prevSnapshotTime, startTime.Unix(), expectedSeconds/2) {
|
||||
c.Logger.Info("skipping new-VM detection due to gap between snapshots", "prev_table", prevTableName, "prev_snapshot_unix", prevSnapshotTime, "current_snapshot_unix", startTime.Unix())
|
||||
// Skip only if snapshots are much closer together than the configured cadence (e.g., rerun inside half interval).
|
||||
if SnapshotTooSoon(prevSnapshotTime, startTime.Unix(), expectedSeconds) {
|
||||
c.Logger.Info("skipping new-VM detection because snapshots are too close together", "prev_table", prevTableName, "prev_snapshot_unix", prevSnapshotTime, "current_snapshot_unix", startTime.Unix(), "expected_interval_seconds", expectedSeconds)
|
||||
} else {
|
||||
newCount = countNewFromPrevious(ctx, dbConn, prevTableName, url, presentSnapshots)
|
||||
if newCount > 0 {
|
||||
|
||||
Reference in New Issue
Block a user