perf(comms): alarms-only seed, capped buffers, at-least-once audit pull

This commit is contained in:
Joseph Doherty
2026-08-14 21:10:19 -04:00
parent 1040dc0fcc
commit 2ce0ad7ed1
30 changed files with 1941 additions and 482 deletions
@@ -64,6 +64,35 @@ public static class ScadaBridgeTelemetry
Meter.CreateCounter<long>("scadabridge.site.alarm_cache.reconnects", unit: "1",
description: "Live-alarm aggregator site-wide gRPC stream reconnects (NodeA↔NodeB flip or reconcile-driven reopen).");
/// <summary>
/// Incremented for each live delta evicted from a per-site live-alarm aggregator's
/// bounded pre-seed buffer (drop-oldest, WP2.3). Non-zero means a seed/reconcile
/// fan-out ran long enough for the delta storm behind it to exceed the cap — the
/// dropped transitions are recovered by the fan-out's authoritative snapshot, but a
/// sustained climb points at a slow site.
/// </summary>
private static readonly Counter<long> _liveAlarmBufferDrops =
Meter.CreateCounter<long>("scadabridge.site.alarm_cache.buffer_dropped", unit: "1",
description: "Live deltas evicted from a live-alarm aggregator's bounded pre-seed buffer (drop-oldest).");
/// <summary>
/// Incremented for each debug event evicted from a central debug session's bounded
/// pre-snapshot buffer (drop-oldest, WP2.3). The Debug View is lossy-under-backpressure
/// by design; this makes the loss measurable instead of unbounded memory growth.
/// </summary>
private static readonly Counter<long> _debugPreSnapshotDrops =
Meter.CreateCounter<long>("scadabridge.central.debug_view.presnapshot_dropped", unit: "1",
description: "Debug events evicted from a central debug session's bounded pre-snapshot buffer (drop-oldest).");
/// <summary>
/// Incremented for each event evicted from a site-hosted gRPC stream's bounded send
/// channel, tagged by stream kind (<c>instance</c> = Debug View, <c>site-alarms</c> =
/// the site-wide alarm feed behind the operator Alarm Summary).
/// </summary>
private static readonly Counter<long> _siteStreamEventDrops =
Meter.CreateCounter<long>("scadabridge.site.stream.events_dropped", unit: "1",
description: "Events evicted from a site gRPC stream's bounded send channel, tagged by stream kind.");
// ---------------- Observable gauges ----------------
/// <summary>Current count of open site connections, mutated via <see cref="Interlocked"/>.</summary>
@@ -136,6 +165,19 @@ public static class ScadaBridgeTelemetry
/// <summary>Records that a per-site live-alarm aggregator re-established its site-wide gRPC stream.</summary>
public static void RecordLiveAlarmStreamReconnect() => _liveAlarmStreamReconnects.Add(1);
/// <summary>Records live deltas evicted from a live-alarm aggregator's bounded pre-seed buffer.</summary>
/// <param name="count">Number of deltas evicted.</param>
public static void RecordLiveAlarmBufferDrop(long count = 1) => _liveAlarmBufferDrops.Add(count);
/// <summary>Records debug events evicted from a debug session's bounded pre-snapshot buffer.</summary>
/// <param name="count">Number of events evicted.</param>
public static void RecordDebugPreSnapshotDrop(long count = 1) => _debugPreSnapshotDrops.Add(count);
/// <summary>Records an event evicted from a site gRPC stream's bounded send channel.</summary>
/// <param name="streamKind">Stream kind tag (<c>instance</c> or <c>site-alarms</c>).</param>
public static void RecordSiteStreamEventDropped(string streamKind) =>
_siteStreamEventDrops.Add(1, new KeyValuePair<string, object?>("stream", streamKind));
/// <summary>
/// Registers the provider the StoreAndForward queue-depth gauge reads on each observation.
/// A later task supplies a provider that reads the real StoreAndForward depth. A null