refactor(health): move ICentralHealthAggregator and SiteHealthState to Commons (ScadaBridge#71)
Interface goes to Commons.Interfaces.Services and the state record to Commons.Messages.Health, so CentralCommunicationActor no longer needs the HealthMonitoring namespace. Implementation stays in HealthMonitoring. Claude-Session: https://claude.ai/code/session_01GT67AEHd2Acv1YPwGfXEoV
This commit is contained in:
@@ -10,7 +10,7 @@ The component code lives in `src/ZB.MOM.WW.ScadaBridge.HealthMonitoring/`:
|
|||||||
|
|
||||||
- `SiteHealthCollector` / `ISiteHealthCollector` — the site-side thread-safe accumulator that other site subsystems push metrics into. Script Actors, Alarm Actors, DCL connection actors, and the Audit Log bridge all call into this singleton.
|
- `SiteHealthCollector` / `ISiteHealthCollector` — the site-side thread-safe accumulator that other site subsystems push metrics into. Script Actors, Alarm Actors, DCL connection actors, and the Audit Log bridge all call into this singleton.
|
||||||
- `HealthReportSender` — a `BackgroundService` that ticks every `ReportInterval` (30 s), atomically drains the collector into a `SiteHealthReport`, stamps a monotonic sequence number, and fires it to central over `IHealthReportTransport` (Akka Tell, fire-and-forget). Only the active node sends — the standby runs the loop but skips the send.
|
- `HealthReportSender` — a `BackgroundService` that ticks every `ReportInterval` (30 s), atomically drains the collector into a `SiteHealthReport`, stamps a monotonic sequence number, and fires it to central over `IHealthReportTransport` (Akka Tell, fire-and-forget). Only the active node sends — the standby runs the loop but skips the send.
|
||||||
- `CentralHealthAggregator` / `ICentralHealthAggregator` — the central-side `BackgroundService` and in-memory store. Receives `SiteHealthReport` messages, applies them atomically via compare-and-swap on `SiteHealthState` records, and runs a periodic offline-detection sweep.
|
- `CentralHealthAggregator` / `ICentralHealthAggregator` — the central-side `BackgroundService` and in-memory store. Receives `SiteHealthReport` messages, applies them atomically via compare-and-swap on `SiteHealthState` records, and runs a periodic offline-detection sweep. The contract types `ICentralHealthAggregator` (`Commons.Interfaces.Services`) and `SiteHealthState` (`Commons.Messages.Health`) live in Commons so consumers (e.g. `CentralCommunicationActor`) need not reference this project for them; the implementation stays here.
|
||||||
- `CentralHealthReportLoop` — central-only counterpart to `HealthReportSender`: generates a synthetic `SiteHealthReport` for the central cluster itself (site ID `$central`) so central appears as a first-class card on `/monitoring/health`. Only the Primary (leader) node generates reports.
|
- `CentralHealthReportLoop` — central-only counterpart to `HealthReportSender`: generates a synthetic `SiteHealthReport` for the central cluster itself (site ID `$central`) so central appears as a first-class card on `/monitoring/health`. Only the Primary (leader) node generates reports.
|
||||||
- `SiteHealthState` — immutable record holding the latest report, last-heartbeat timestamp, sequence number, and online/offline flag for one site. Handed directly to UI callers; never torn because the aggregator swaps it atomically.
|
- `SiteHealthState` — immutable record holding the latest report, last-heartbeat timestamp, sequence number, and online/offline flag for one site. Handed directly to UI callers; never torn because the aggregator swaps it atomically.
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
using ZB.MOM.WW.ScadaBridge.Commons.Interfaces.Services;
|
||||||
using ZB.MOM.WW.ScadaBridge.AuditLog.Payload;
|
using ZB.MOM.WW.ScadaBridge.AuditLog.Payload;
|
||||||
|
|
||||||
namespace ZB.MOM.WW.ScadaBridge.AuditLog.Central;
|
namespace ZB.MOM.WW.ScadaBridge.AuditLog.Central;
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
@page "/monitoring/health"
|
@page "/monitoring/health"
|
||||||
@attribute [Authorize]
|
@attribute [Authorize]
|
||||||
|
@using ZB.MOM.WW.ScadaBridge.Commons.Interfaces.Services
|
||||||
|
@using ZB.MOM.WW.ScadaBridge.Commons.Messages.Health
|
||||||
@using ZB.MOM.WW.ScadaBridge.CentralUI.Components.Health
|
@using ZB.MOM.WW.ScadaBridge.CentralUI.Components.Health
|
||||||
@using ZB.MOM.WW.ScadaBridge.CentralUI.Services
|
@using ZB.MOM.WW.ScadaBridge.CentralUI.Services
|
||||||
@using ZB.MOM.WW.ScadaBridge.Commons.Types
|
@using ZB.MOM.WW.ScadaBridge.Commons.Types
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
using ZB.MOM.WW.ScadaBridge.Commons.Interfaces.Services;
|
||||||
using Microsoft.AspNetCore.Components.Authorization;
|
using Microsoft.AspNetCore.Components.Authorization;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Microsoft.Extensions.Options;
|
using Microsoft.Extensions.Options;
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
using ZB.MOM.WW.ScadaBridge.Commons.Interfaces.Services;
|
||||||
using Microsoft.AspNetCore.Components.Authorization;
|
using Microsoft.AspNetCore.Components.Authorization;
|
||||||
using ZB.MOM.WW.ScadaBridge.CentralUI.Auth;
|
using ZB.MOM.WW.ScadaBridge.CentralUI.Auth;
|
||||||
using ZB.MOM.WW.ScadaBridge.Security;
|
using ZB.MOM.WW.ScadaBridge.Security;
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
using ZB.MOM.WW.ScadaBridge.Commons.Interfaces.Services;
|
||||||
using ZB.MOM.WW.ScadaBridge.Commons.Interfaces.Repositories;
|
using ZB.MOM.WW.ScadaBridge.Commons.Interfaces.Repositories;
|
||||||
using ZB.MOM.WW.ScadaBridge.Commons.Types.Enums;
|
using ZB.MOM.WW.ScadaBridge.Commons.Types.Enums;
|
||||||
using ZB.MOM.WW.ScadaBridge.HealthMonitoring;
|
using ZB.MOM.WW.ScadaBridge.HealthMonitoring;
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
using ZB.MOM.WW.ScadaBridge.Commons.Interfaces.Services;
|
||||||
using ZB.MOM.WW.ScadaBridge.Commons.Types;
|
using ZB.MOM.WW.ScadaBridge.Commons.Types;
|
||||||
using ZB.MOM.WW.ScadaBridge.Commons.Types.Audit;
|
using ZB.MOM.WW.ScadaBridge.Commons.Types.Audit;
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
using ZB.MOM.WW.ScadaBridge.Commons.Interfaces.Services;
|
||||||
using ZB.MOM.WW.ScadaBridge.Commons.Types.Enums;
|
using ZB.MOM.WW.ScadaBridge.Commons.Types.Enums;
|
||||||
|
|
||||||
namespace ZB.MOM.WW.ScadaBridge.CentralUI.Services;
|
namespace ZB.MOM.WW.ScadaBridge.CentralUI.Services;
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
using ZB.MOM.WW.ScadaBridge.Commons.Interfaces.Services;
|
||||||
using ZB.MOM.WW.Audit;
|
using ZB.MOM.WW.Audit;
|
||||||
using ZB.MOM.WW.ScadaBridge.Commons.Types;
|
using ZB.MOM.WW.ScadaBridge.Commons.Types;
|
||||||
using ZB.MOM.WW.ScadaBridge.Commons.Types.Audit;
|
using ZB.MOM.WW.ScadaBridge.Commons.Types.Audit;
|
||||||
|
|||||||
+2
-2
@@ -1,6 +1,6 @@
|
|||||||
using ZB.MOM.WW.ScadaBridge.Commons.Messages.Health;
|
using ZB.MOM.WW.ScadaBridge.Commons.Messages.Health;
|
||||||
|
|
||||||
namespace ZB.MOM.WW.ScadaBridge.HealthMonitoring;
|
namespace ZB.MOM.WW.ScadaBridge.Commons.Interfaces.Services;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Interface for central-side health aggregation.
|
/// Interface for central-side health aggregation.
|
||||||
@@ -21,7 +21,7 @@ public interface ICentralHealthAggregator
|
|||||||
/// cadence is owned by the Cluster Infrastructure / <c>SiteCommunicationActor</c>
|
/// cadence is owned by the Cluster Infrastructure / <c>SiteCommunicationActor</c>
|
||||||
/// (the application-level heartbeat to central, sent every
|
/// (the application-level heartbeat to central, sent every
|
||||||
/// <c>CommunicationOptions.TransportHeartbeatInterval</c> — 5s by default);
|
/// <c>CommunicationOptions.TransportHeartbeatInterval</c> — 5s by default);
|
||||||
/// the 60s <see cref="HealthMonitoringOptions.OfflineTimeout"/> therefore
|
/// the 60s <c>HealthMonitoringOptions.OfflineTimeout</c> therefore
|
||||||
/// tolerates several missed heartbeats. A heartbeat for a site with no
|
/// tolerates several missed heartbeats. A heartbeat for a site with no
|
||||||
/// aggregator state yet (e.g. just after a central restart/failover)
|
/// aggregator state yet (e.g. just after a central restart/failover)
|
||||||
/// registers that site as online with no
|
/// registers that site as online with no
|
||||||
+4
-6
@@ -1,6 +1,4 @@
|
|||||||
using ZB.MOM.WW.ScadaBridge.Commons.Messages.Health;
|
namespace ZB.MOM.WW.ScadaBridge.Commons.Messages.Health;
|
||||||
|
|
||||||
namespace ZB.MOM.WW.ScadaBridge.HealthMonitoring;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// In-memory state for a single site's health, stored by the central aggregator.
|
/// In-memory state for a single site's health, stored by the central aggregator.
|
||||||
@@ -59,7 +57,7 @@ public sealed record SiteHealthState
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets a value indicating whether the site is online (heartbeats still
|
/// Gets a value indicating whether the site is online (heartbeats still
|
||||||
/// arriving) but has sent no full <see cref="SiteHealthReport"/> within
|
/// arriving) but has sent no full <see cref="SiteHealthReport"/> within
|
||||||
/// <see cref="HealthMonitoringOptions.MetricsStaleTimeout"/>. This is a signal
|
/// <c>HealthMonitoringOptions.MetricsStaleTimeout</c>. This is a signal
|
||||||
/// <em>distinct</em> from liveness: a site whose HealthReportSender died keeps
|
/// <em>distinct</em> from liveness: a site whose HealthReportSender died keeps
|
||||||
/// heartbeating and would otherwise show "online with frozen metrics forever".
|
/// heartbeating and would otherwise show "online with frozen metrics forever".
|
||||||
/// Cleared whenever a fresh report is processed. Heartbeats never set or clear
|
/// Cleared whenever a fresh report is processed. Heartbeats never set or clear
|
||||||
@@ -69,12 +67,12 @@ public sealed record SiteHealthState
|
|||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the instant this site's LocalDb replication oplog backlog first rose above
|
/// Gets the instant this site's LocalDb replication oplog backlog first rose above
|
||||||
/// <see cref="HealthMonitoringOptions.LocalDbBacklogThreshold"/> and stayed there, or
|
/// <c>HealthMonitoringOptions.LocalDbBacklogThreshold</c> and stayed there, or
|
||||||
/// <c>null</c> if the backlog is not currently above it (register row 33).
|
/// <c>null</c> if the backlog is not currently above it (register row 33).
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <remarks>
|
/// <remarks>
|
||||||
/// The anchor for the *sustained* backlog badge: the badge shows only once
|
/// The anchor for the *sustained* backlog badge: the badge shows only once
|
||||||
/// <see cref="HealthMonitoringOptions.LocalDbBacklogSustainedFor"/> has elapsed since this
|
/// <c>HealthMonitoringOptions.LocalDbBacklogSustainedFor</c> has elapsed since this
|
||||||
/// instant. Holding a start time rather than a boolean is what makes the signal survive the
|
/// instant. Holding a start time rather than a boolean is what makes the signal survive the
|
||||||
/// expected daily purge burst — that spike raises the backlog for a drain's worth of
|
/// expected daily purge burst — that spike raises the backlog for a drain's worth of
|
||||||
/// reports and then clears this back to null, never reaching the dwell.
|
/// reports and then clears this back to null, never reaching the dwell.
|
||||||
@@ -1,3 +1,4 @@
|
|||||||
|
using ZB.MOM.WW.ScadaBridge.Commons.Interfaces.Services;
|
||||||
using Akka.Actor;
|
using Akka.Actor;
|
||||||
using Akka.Cluster.Tools.PublishSubscribe;
|
using Akka.Cluster.Tools.PublishSubscribe;
|
||||||
using Akka.Event;
|
using Akka.Event;
|
||||||
@@ -10,7 +11,6 @@ using ZB.MOM.WW.ScadaBridge.Commons.Messages.Communication;
|
|||||||
using ZB.MOM.WW.ScadaBridge.Commons.Messages.Deployment;
|
using ZB.MOM.WW.ScadaBridge.Commons.Messages.Deployment;
|
||||||
using ZB.MOM.WW.ScadaBridge.Commons.Messages.Health;
|
using ZB.MOM.WW.ScadaBridge.Commons.Messages.Health;
|
||||||
using ZB.MOM.WW.ScadaBridge.Commons.Messages.Notification;
|
using ZB.MOM.WW.ScadaBridge.Commons.Messages.Notification;
|
||||||
using ZB.MOM.WW.ScadaBridge.HealthMonitoring;
|
|
||||||
|
|
||||||
namespace ZB.MOM.WW.ScadaBridge.Communication.Actors;
|
namespace ZB.MOM.WW.ScadaBridge.Communication.Actors;
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
using ZB.MOM.WW.ScadaBridge.Commons.Interfaces.Services;
|
||||||
using Akka.Actor;
|
using Akka.Actor;
|
||||||
using Google.Protobuf.WellKnownTypes;
|
using Google.Protobuf.WellKnownTypes;
|
||||||
using Grpc.Core;
|
using Grpc.Core;
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
using ZB.MOM.WW.ScadaBridge.Commons.Interfaces.Services;
|
||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
using Microsoft.Extensions.Hosting;
|
using Microsoft.Extensions.Hosting;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
using ZB.MOM.WW.ScadaBridge.Commons.Interfaces.Services;
|
||||||
using Microsoft.Extensions.Hosting;
|
using Microsoft.Extensions.Hosting;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using Microsoft.Extensions.Options;
|
using Microsoft.Extensions.Options;
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
using ZB.MOM.WW.ScadaBridge.Commons.Interfaces.Services;
|
||||||
using ZB.MOM.WW.ScadaBridge.Commons.Interfaces.Kpi;
|
using ZB.MOM.WW.ScadaBridge.Commons.Interfaces.Kpi;
|
||||||
|
|
||||||
namespace ZB.MOM.WW.ScadaBridge.HealthMonitoring.Kpi;
|
namespace ZB.MOM.WW.ScadaBridge.HealthMonitoring.Kpi;
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
using ZB.MOM.WW.ScadaBridge.Commons.Interfaces.Services;
|
||||||
using ZB.MOM.WW.ScadaBridge.Commons.Entities.Kpi;
|
using ZB.MOM.WW.ScadaBridge.Commons.Entities.Kpi;
|
||||||
using ZB.MOM.WW.ScadaBridge.Commons.Interfaces.Kpi;
|
using ZB.MOM.WW.ScadaBridge.Commons.Interfaces.Kpi;
|
||||||
using ZB.MOM.WW.ScadaBridge.Commons.Types.Enums;
|
using ZB.MOM.WW.ScadaBridge.Commons.Types.Enums;
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
using ZB.MOM.WW.ScadaBridge.Commons.Interfaces.Services;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Microsoft.Extensions.DependencyInjection.Extensions;
|
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||||
using Microsoft.Extensions.Hosting;
|
using Microsoft.Extensions.Hosting;
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
using ZB.MOM.WW.ScadaBridge.Commons.Interfaces.Services;
|
||||||
using System.Security.Claims;
|
using System.Security.Claims;
|
||||||
using ZB.MOM.WW.ScadaBridge.Security;
|
using ZB.MOM.WW.ScadaBridge.Security;
|
||||||
using Akka.Actor;
|
using Akka.Actor;
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
using ZB.MOM.WW.ScadaBridge.Commons.Interfaces.Services;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using Microsoft.EntityFrameworkCore.Diagnostics;
|
using Microsoft.EntityFrameworkCore.Diagnostics;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
using ZB.MOM.WW.ScadaBridge.Commons.Interfaces.Services;
|
||||||
using System.Security.Claims;
|
using System.Security.Claims;
|
||||||
using Microsoft.AspNetCore.Components.Authorization;
|
using Microsoft.AspNetCore.Components.Authorization;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
|||||||
+1
@@ -1,3 +1,4 @@
|
|||||||
|
using ZB.MOM.WW.ScadaBridge.Commons.Interfaces.Services;
|
||||||
using NSubstitute;
|
using NSubstitute;
|
||||||
using ZB.MOM.WW.ScadaBridge.CentralUI.Services;
|
using ZB.MOM.WW.ScadaBridge.CentralUI.Services;
|
||||||
using ZB.MOM.WW.ScadaBridge.Commons.Entities.Sites;
|
using ZB.MOM.WW.ScadaBridge.Commons.Entities.Sites;
|
||||||
|
|||||||
+1
@@ -1,3 +1,4 @@
|
|||||||
|
using ZB.MOM.WW.ScadaBridge.Commons.Interfaces.Services;
|
||||||
using Akka.Actor;
|
using Akka.Actor;
|
||||||
using Akka.TestKit.Xunit2;
|
using Akka.TestKit.Xunit2;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
using ZB.MOM.WW.ScadaBridge.Commons.Interfaces.Services;
|
||||||
using Akka.Actor;
|
using Akka.Actor;
|
||||||
using Akka.TestKit.Xunit2;
|
using Akka.TestKit.Xunit2;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
using ZB.MOM.WW.ScadaBridge.Commons.Interfaces.Services;
|
||||||
using Akka.Actor;
|
using Akka.Actor;
|
||||||
using Akka.TestKit.Xunit2;
|
using Akka.TestKit.Xunit2;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
using ZB.MOM.WW.ScadaBridge.Commons.Interfaces.Services;
|
||||||
using Microsoft.Extensions.Logging.Abstractions;
|
using Microsoft.Extensions.Logging.Abstractions;
|
||||||
using Microsoft.Extensions.Options;
|
using Microsoft.Extensions.Options;
|
||||||
using ZB.MOM.WW.ScadaBridge.Commons.Messages.Health;
|
using ZB.MOM.WW.ScadaBridge.Commons.Messages.Health;
|
||||||
|
|||||||
+1
@@ -1,3 +1,4 @@
|
|||||||
|
using ZB.MOM.WW.ScadaBridge.Commons.Interfaces.Services;
|
||||||
using ZB.MOM.WW.ScadaBridge.Commons.Messages.Health;
|
using ZB.MOM.WW.ScadaBridge.Commons.Messages.Health;
|
||||||
using ZB.MOM.WW.ScadaBridge.Commons.Types;
|
using ZB.MOM.WW.ScadaBridge.Commons.Types;
|
||||||
using ZB.MOM.WW.ScadaBridge.Commons.Types.Enums;
|
using ZB.MOM.WW.ScadaBridge.Commons.Types.Enums;
|
||||||
|
|||||||
+1
@@ -1,3 +1,4 @@
|
|||||||
|
using ZB.MOM.WW.ScadaBridge.Commons.Interfaces.Services;
|
||||||
using ZB.MOM.WW.ScadaBridge.Commons.Entities.Kpi;
|
using ZB.MOM.WW.ScadaBridge.Commons.Entities.Kpi;
|
||||||
using ZB.MOM.WW.ScadaBridge.Commons.Messages.Health;
|
using ZB.MOM.WW.ScadaBridge.Commons.Messages.Health;
|
||||||
using ZB.MOM.WW.ScadaBridge.Commons.Types;
|
using ZB.MOM.WW.ScadaBridge.Commons.Types;
|
||||||
|
|||||||
Reference in New Issue
Block a user