mirror of
https://github.com/rcourtman/Pulse.git
synced 2026-10-27 05:57:27 +00:00
8823440f33
In mock mode the unified view is keyed on the fixture data version, which advances on every metric tick, and building it for the default 1,776-resource estate costs about half a second of CPU (many seconds on a starved process). #2778 moved the metrics-target lookup onto the fixture structure revision; the other callers that read only what the estate lists and how it connects still rebuilt the whole view after each tick. At startup they made 42 view requests, all misses, and with no client connected the monitor tick alone rebuilt the estate about every nine seconds. Callers that read identity and topology now share the view built for the current structure revision and operator links (currentStructureUnifiedStateView, GetUnifiedStructureReadState): the Docker-alert prune, the workload chart prewarm, the demo Patrol resolver, and the host-agent evaluation, which also lists nodes only when an offline host names a linked node. The connection-degraded alert feed keeps only platform rows, so it no longer reads the hosts, their desired-config fingerprints or the PBS instances that only feed agent rows and a host alias its snapshot drops. The mock storage chart is not one of them: a linked pool takes its capacity from whichever source was seen last, which a tick can move without a structure change. It keeps the data-version view, read once per request instead of once per uncached pool. The per-node polling lookups of a monitor that keeps real polling in mock mode (linkedHostForNode, getHostAgentTemperatureForNode, carriedTemperatureOutlivesAgentLease) read a host's status, disks and sensors, which a tick moves, so they stay on the data-version view. On pulse-dev (one pinned core, host load 30 to 110, probe builds): a start built the estate view twice before the listener answered with the wiring change alone and once with this; with no client connected the process built the estate 33 times in 299 s and used 12.3 s of CPU over a 180 s window, against twice and 3.3 s with this change.
52 lines
2.7 KiB
Go
52 lines
2.7 KiB
Go
package monitoring
|
|
|
|
import (
|
|
"github.com/rcourtman/pulse-go-rewrite/internal/mock"
|
|
"github.com/rcourtman/pulse-go-rewrite/internal/unifiedresources"
|
|
)
|
|
|
|
// mockMetricsTarget resolves a canonical resource ID to its metrics-store
|
|
// target in mock mode. The second result is false when mock mode is off, so
|
|
// the caller takes its ordinary path; when it is true the answer is final for
|
|
// this structure, a nil target meaning the view captured no metrics target for
|
|
// the ID (the estate does not list it, or lists a resource that has none, such
|
|
// as a VMware network); the caller still tries the raw resource store.
|
|
//
|
|
// Alert evaluation resolves a target for every resource and every windowed
|
|
// metric (CPU by default) on every pass, through MetricsTargetForResource.
|
|
// The mock view that answers it is cached per fixture data version, and that
|
|
// version advances on every metric tick (2 s by default). Rebuilding the view
|
|
// ingests the whole estate twice (the memoized fixture snapshot, then the
|
|
// view's own registry), about half a second of CPU for the default estate
|
|
// (1,776 resources) on an idle core. A build that takes longer than one tick publishes
|
|
// its view under an already-stale version, so the next lookup rebuilds again:
|
|
// on a host with CPU to spare that costs one build per tick, but when the
|
|
// process is starved (a loaded dev VM, a small demo host) the cache never
|
|
// hits, every lookup in the pass builds an estate, and the monitor never
|
|
// finishes its first evaluation. Startup stalled in exactly that state,
|
|
// before the listener opened, with the watchdog dump parked in the view build
|
|
// beneath evaluateMetricWindow.
|
|
//
|
|
// A metrics target depends only on identity inputs: a resource's type, its
|
|
// source mappings, and the technology, Docker container ID and disk identity
|
|
// of its facets (unifiedresources.BuildMetricsTarget), falling back to the
|
|
// resource's own MetricsTarget. A metric tick moves values and timestamps,
|
|
// never those inputs (TestMetricTicksNeverChangeTheFixtureStructure), so the
|
|
// captured targets of a view built at any data version of the current
|
|
// structure answer the lookup. A data-version change alone therefore never
|
|
// triggers a build here: only a structural change (mock mode toggled, the
|
|
// fixture reconfigured) or a link change makes the next lookup rebuild the
|
|
// view. Two lookups that miss together can each still build one, and a cold
|
|
// cache builds even for an ID the estate does not list.
|
|
func (m *Monitor) mockMetricsTarget(resourceID string) (*unifiedresources.MetricsTarget, bool) {
|
|
if m == nil || !mock.IsMockEnabled() {
|
|
return nil, false
|
|
}
|
|
|
|
view := m.currentStructureUnifiedStateView()
|
|
if view.metricsTargets == nil {
|
|
return nil, true
|
|
}
|
|
return view.metricsTargets.MetricsTargetForResource(resourceID), true
|
|
}
|