mirror of
https://github.com/rcourtman/Pulse.git
synced 2026-10-14 08:10:26 +00:00
1d9e66b24c
The public demo runs PULSE_MOCK_UPDATE_INTERVAL=60s, which stretches the 10-cohort supplemental rotation to 600s while the unified registry still marks TrueNAS/VMware/availability sources stale after 120s. Every row those sources own spent ~80% of each rotation flagged as a degraded stale source, so the TrueNAS Storage tab read Healthy 0 / Attention 21 (and the vSphere page all-Attention) despite healthy fixture data. Rebase provider-backed fixtures every tick once the rotation would outlive the 120s freshness budget (at slow ticks that is cheaper per wall-clock second than the default 2s config's once-per-20s cadence), and derive mock supplemental stale thresholds from the actual refresh cadence the same way PVE/PBS/PMG thresholds already derive from their polling intervals. Split the supplemental uptime step so per-tick refreshes do not advance PBS uptime by the rotation-scaled step.
109 lines
3.6 KiB
Go
109 lines
3.6 KiB
Go
package monitoring
|
|
|
|
import (
|
|
"time"
|
|
|
|
"github.com/rcourtman/pulse-go-rewrite/internal/config"
|
|
"github.com/rcourtman/pulse-go-rewrite/internal/mock"
|
|
"github.com/rcourtman/pulse-go-rewrite/internal/unifiedresources"
|
|
)
|
|
|
|
const (
|
|
defaultProxmoxResourceStaleThreshold = 60 * time.Second
|
|
defaultPlatformResourceStaleThreshold = 120 * time.Second
|
|
)
|
|
|
|
// ResourceStaleThresholdsForConfig derives canonical resource freshness from
|
|
// polling cadence. A source should not be considered stale until it has missed
|
|
// at least one expected poll cycle plus the normal interval.
|
|
func ResourceStaleThresholdsForConfig(cfg *config.Config) map[unifiedresources.DataSource]time.Duration {
|
|
return resourceStaleThresholdsForConfig(cfg, mock.IsMockEnabled(), mock.SupplementalRefreshInterval)
|
|
}
|
|
|
|
func resourceStaleThresholdsForConfig(
|
|
cfg *config.Config,
|
|
mockEnabled bool,
|
|
mockSupplementalCadence func() time.Duration,
|
|
) map[unifiedresources.DataSource]time.Duration {
|
|
thresholds := map[unifiedresources.DataSource]time.Duration{
|
|
unifiedresources.SourceProxmox: resourceStaleThresholdForPollInterval(
|
|
effectivePVEPollingIntervalForConfig(cfg),
|
|
defaultProxmoxResourceStaleThreshold,
|
|
),
|
|
unifiedresources.SourcePBS: resourceStaleThresholdForPollInterval(
|
|
effectivePlatformPollingIntervalForConfig(cfg, "pbs"),
|
|
defaultPlatformResourceStaleThreshold,
|
|
),
|
|
unifiedresources.SourcePMG: resourceStaleThresholdForPollInterval(
|
|
effectivePlatformPollingIntervalForConfig(cfg, "pmg"),
|
|
defaultPlatformResourceStaleThreshold,
|
|
),
|
|
}
|
|
// Mock mode's provider-backed fixtures (TrueNAS, VMware, availability)
|
|
// deliver on the mock update loop's supplemental cadence rather than a
|
|
// real poll schedule. Derive their freshness from that cadence the same
|
|
// way the entries above derive theirs, so a slow mock tick (e.g. a large
|
|
// PULSE_MOCK_UPDATE_INTERVAL on the public demo) does not flag every
|
|
// provider-owned row as a stale source between refreshes.
|
|
if mockEnabled && mockSupplementalCadence != nil {
|
|
supplemental := resourceStaleThresholdForPollInterval(
|
|
mockSupplementalCadence(),
|
|
defaultPlatformResourceStaleThreshold,
|
|
)
|
|
thresholds[unifiedresources.SourceTrueNAS] = supplemental
|
|
thresholds[unifiedresources.SourceVMware] = supplemental
|
|
thresholds[unifiedresources.SourceAvailability] = supplemental
|
|
}
|
|
return thresholds
|
|
}
|
|
|
|
func (m *Monitor) resourceStaleThresholds() map[unifiedresources.DataSource]time.Duration {
|
|
if m == nil {
|
|
return ResourceStaleThresholdsForConfig(nil)
|
|
}
|
|
return ResourceStaleThresholdsForConfig(m.config)
|
|
}
|
|
|
|
func (m *Monitor) pveNodeOfflineGracePeriod() time.Duration {
|
|
return m.resourceStaleThresholds()[unifiedresources.SourceProxmox]
|
|
}
|
|
|
|
func effectivePVEPollingIntervalForConfig(cfg *config.Config) time.Duration {
|
|
const minInterval = 10 * time.Second
|
|
const maxInterval = time.Hour
|
|
|
|
interval := minInterval
|
|
if cfg != nil && cfg.PVEPollingInterval > 0 {
|
|
interval = cfg.PVEPollingInterval
|
|
}
|
|
return clampInterval(interval, minInterval, maxInterval)
|
|
}
|
|
|
|
func effectivePlatformPollingIntervalForConfig(cfg *config.Config, platform string) time.Duration {
|
|
if cfg == nil {
|
|
return 60 * time.Second
|
|
}
|
|
switch platform {
|
|
case "pbs":
|
|
return clampInterval(cfg.PBSPollingInterval, 10*time.Second, time.Hour)
|
|
case "pmg":
|
|
return clampInterval(cfg.PMGPollingInterval, 10*time.Second, time.Hour)
|
|
default:
|
|
return 60 * time.Second
|
|
}
|
|
}
|
|
|
|
func resourceStaleThresholdForPollInterval(interval, minimum time.Duration) time.Duration {
|
|
if minimum <= 0 {
|
|
minimum = defaultPlatformResourceStaleThreshold
|
|
}
|
|
if interval <= 0 {
|
|
return minimum
|
|
}
|
|
threshold := interval * 2
|
|
if threshold < minimum {
|
|
return minimum
|
|
}
|
|
return threshold
|
|
}
|