mirror of
https://github.com/rcourtman/Pulse.git
synced 2026-10-23 20:25:56 +00:00
13bd250328
While a standalone agent stayed offline across a restart, every canonical read-state lookup overlaid it from host continuity by building a whole registry clone. Alert evaluation makes one lookup per resource per poll, so for up to 72 hours each poll rebuilt the registry once per resource. Each lookup also called GetLiveHostsSnapshot twice, and that deep-copied every guest in the monitor state to return the hosts. The adapter now keeps the last continuity overlay, keyed by registry pointer, LastRebuiltAt, and a fingerprint of the requested records that leaves out the build-time UpdatedAt stamp. It reuses the overlay for at most two seconds, because the overlay evaluates source staleness when it is built, and it never mutates the live adapter. GetLiveHostsSnapshot now copies only hosts through State.GetHosts, which also removes a full state copy from every agent report and config fetch. With one offline standalone agent, a read-state lookup at 2,080 synthetic resources went from 136 ms and 95 MB to 74 us and 104 KB. Refs #2199
201 lines
5.6 KiB
Go
201 lines
5.6 KiB
Go
package monitoring
|
|
|
|
import (
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/rcourtman/pulse-go-rewrite/internal/unifiedresources"
|
|
)
|
|
|
|
// MonitoredSystemUsageSnapshot describes whether the monitor can currently
|
|
// supply a canonical monitored-system count that is safe for settings and
|
|
// support context to consume.
|
|
type MonitoredSystemUsageSnapshot struct {
|
|
Count int
|
|
ReadState unifiedresources.ReadState
|
|
Available bool
|
|
UnavailableReason string
|
|
}
|
|
|
|
const (
|
|
MonitoredSystemUsageUnavailableMonitorState = "monitor_state_unavailable"
|
|
MonitoredSystemUsageUnavailableSupplementalInventoryUnsettled = "supplemental_inventory_unsettled"
|
|
MonitoredSystemUsageUnavailableSupplementalInventoryRebuildPending = "supplemental_inventory_rebuild_pending"
|
|
)
|
|
|
|
// MonitoredSystemUsage returns the canonical monitored-system count only when
|
|
// the current unified view is settled enough for settings/support context. When
|
|
// supplemental provider-owned sources are still settling, the result fails
|
|
// closed with Available=false.
|
|
func (m *Monitor) MonitoredSystemUsage() MonitoredSystemUsageSnapshot {
|
|
if m == nil {
|
|
return MonitoredSystemUsageSnapshot{UnavailableReason: MonitoredSystemUsageUnavailableMonitorState}
|
|
}
|
|
|
|
readState := m.GetUnifiedReadStateOrSnapshot()
|
|
if readState == nil {
|
|
return MonitoredSystemUsageSnapshot{UnavailableReason: MonitoredSystemUsageUnavailableMonitorState}
|
|
}
|
|
|
|
orgID := normalizedMonitorUsageOrgID(m)
|
|
readyAt, settled := m.supplementalInventoryReadyAt(orgID)
|
|
if !settled {
|
|
return MonitoredSystemUsageSnapshot{
|
|
ReadState: readState,
|
|
UnavailableReason: MonitoredSystemUsageUnavailableSupplementalInventoryUnsettled,
|
|
}
|
|
}
|
|
if !readyAt.IsZero() {
|
|
freshness := m.currentUnifiedResourceFreshness()
|
|
if freshness.IsZero() || freshness.Before(readyAt) {
|
|
return MonitoredSystemUsageSnapshot{
|
|
ReadState: readState,
|
|
UnavailableReason: MonitoredSystemUsageUnavailableSupplementalInventoryRebuildPending,
|
|
}
|
|
}
|
|
}
|
|
|
|
readState = m.readStateWithStandaloneHostContinuity(readState)
|
|
|
|
return MonitoredSystemUsageSnapshot{
|
|
Count: unifiedresources.MonitoredSystemCount(readState),
|
|
ReadState: readState,
|
|
Available: true,
|
|
}
|
|
}
|
|
|
|
func (m *Monitor) readStateWithStandaloneHostContinuity(
|
|
readState unifiedresources.ReadState,
|
|
) unifiedresources.ReadState {
|
|
if m == nil || readState == nil {
|
|
return readState
|
|
}
|
|
|
|
entries := m.recentStandaloneHostContinuityEntries()
|
|
if len(entries) == 0 {
|
|
return readState
|
|
}
|
|
|
|
liveHosts := m.GetLiveHostsSnapshot()
|
|
liveHostIDs := make(map[string]struct{}, len(liveHosts))
|
|
for _, host := range liveHosts {
|
|
if id := strings.TrimSpace(host.ID); id != "" {
|
|
liveHostIDs[id] = struct{}{}
|
|
}
|
|
}
|
|
|
|
existingAgentIDs := make(map[string]struct{}, len(readState.Hosts()))
|
|
for _, host := range readState.Hosts() {
|
|
if host == nil {
|
|
continue
|
|
}
|
|
if agentID := strings.TrimSpace(host.AgentID()); agentID != "" {
|
|
existingAgentIDs[agentID] = struct{}{}
|
|
}
|
|
if resourceID := strings.TrimSpace(host.ID()); resourceID != "" {
|
|
existingAgentIDs[resourceID] = struct{}{}
|
|
}
|
|
}
|
|
|
|
records := make([]unifiedresources.IngestRecord, 0, len(entries))
|
|
for _, entry := range entries {
|
|
hostID := strings.TrimSpace(entry.HostID)
|
|
if hostID == "" {
|
|
continue
|
|
}
|
|
if _, ok := liveHostIDs[hostID]; ok {
|
|
continue
|
|
}
|
|
if _, ok := existingAgentIDs[hostID]; ok {
|
|
continue
|
|
}
|
|
// A continuity-only row has no live report in this monitor generation.
|
|
// Preserve its last-known identity so the operator can inspect or remove
|
|
// it, but never present persisted telemetry as a current online sighting.
|
|
host := hostFromContinuityEntry(entry)
|
|
host.Status = "offline"
|
|
records = append(records, unifiedresources.HostIngestRecord(host))
|
|
}
|
|
if len(records) == 0 {
|
|
return readState
|
|
}
|
|
return unifiedresources.ReadStateWithHostContinuity(readState, records)
|
|
}
|
|
|
|
func normalizedMonitorUsageOrgID(m *Monitor) string {
|
|
if m == nil {
|
|
return "default"
|
|
}
|
|
orgID := strings.TrimSpace(m.GetOrgID())
|
|
if orgID == "" {
|
|
return "default"
|
|
}
|
|
return orgID
|
|
}
|
|
|
|
func (m *Monitor) supplementalInventoryReadyAt(orgID string) (time.Time, bool) {
|
|
providers := m.supplementalProviderSnapshot()
|
|
if len(providers) == 0 {
|
|
return time.Time{}, true
|
|
}
|
|
|
|
var watermark time.Time
|
|
for _, provider := range providers {
|
|
if provider == nil {
|
|
continue
|
|
}
|
|
|
|
readinessProvider, hasReadiness := provider.(MonitorSupplementalInventoryReadinessProvider)
|
|
if !hasReadiness {
|
|
if len(supplementalProviderOwnedSourcesForOrg(provider, orgID)) > 0 {
|
|
return time.Time{}, false
|
|
}
|
|
continue
|
|
}
|
|
|
|
readyAt, settled := readinessProvider.SupplementalInventoryReadyAt(m, orgID)
|
|
if !settled {
|
|
return time.Time{}, false
|
|
}
|
|
if readyAt.After(watermark) {
|
|
watermark = readyAt
|
|
}
|
|
}
|
|
|
|
return watermark, true
|
|
}
|
|
|
|
func supplementalProviderOwnedSourcesForOrg(
|
|
provider MonitorSupplementalRecordsProvider,
|
|
orgID string,
|
|
) []unifiedresources.DataSource {
|
|
if provider == nil {
|
|
return nil
|
|
}
|
|
|
|
var sources []unifiedresources.DataSource
|
|
if tenantOwner, ok := provider.(interface {
|
|
SnapshotOwnedSourcesForOrg(string) []unifiedresources.DataSource
|
|
}); ok {
|
|
sources = tenantOwner.SnapshotOwnedSourcesForOrg(orgID)
|
|
} else if owner, ok := provider.(interface {
|
|
SnapshotOwnedSources() []unifiedresources.DataSource
|
|
}); ok {
|
|
sources = owner.SnapshotOwnedSources()
|
|
}
|
|
|
|
if len(sources) == 0 {
|
|
return nil
|
|
}
|
|
|
|
out := make([]unifiedresources.DataSource, 0, len(sources))
|
|
for _, source := range sources {
|
|
normalized := unifiedresources.DataSource(strings.ToLower(strings.TrimSpace(string(source))))
|
|
if normalized == "" {
|
|
continue
|
|
}
|
|
out = append(out, normalized)
|
|
}
|
|
return out
|
|
}
|