using ZB.MOM.WW.ScadaBridge.Commons.Messages.Health; using ZB.MOM.WW.ScadaBridge.Commons.Types; using ZB.MOM.WW.ScadaBridge.Commons.Types.Enums; namespace ZB.MOM.WW.ScadaBridge.HealthMonitoring; /// /// Interface for site-side health metric collection. /// Consumed by Site Runtime actors to report errors, and by DCL to report connection health. /// public interface ISiteHealthCollector { /// /// Increments the script error count. /// void IncrementScriptError(); /// /// Increments the alarm error count. /// void IncrementAlarmError(); /// /// Increments the dead letter count. /// void IncrementDeadLetter(); /// /// WP3.1: increments the per-interval count of script/alarm runs SHED because /// MaxConcurrentRunsPerScript runs were already in flight for that script. A raw /// per-interval count like the script/alarm error counters — a sustained non-zero value /// means a trigger is firing faster than its script can complete. Every shed is counted /// here even when its accompanying site event is rate-limited away. /// Default interface implementation is a no-op so existing test fakes continue to /// compile without per-fake updates. /// void IncrementScriptRunShed() { // Default no-op so test fakes do not need to be updated. } /// /// Increment the per-interval count of /// FallbackAuditWriter primary failures. Bridged from the /// IAuditWriteFailureCounter binding registered via /// AddAuditLogHealthMetricsBridge(). /// void IncrementSiteAuditWriteFailures(); /// /// Increment the per-interval count of /// payload-filter redactor over-redactions (header / body / SQL /// parameter stage throws routed to the /// <redacted: redactor error> marker). Bridged from the /// IAuditRedactionFailureCounter binding registered via /// AddAuditLogHealthMetricsBridge(). /// void IncrementAuditRedactionFailure(); /// /// Replace the latest site-local /// audit-queue backlog snapshot (pending count, oldest pending row, /// on-disk file bytes) used by the next call. /// Refreshed periodically by the SiteAuditBacklogReporter hosted /// service so each report carries a recent point-in-time view of the /// site→central drain health. /// /// The audit backlog snapshot. void UpdateSiteAuditBacklog(SiteAuditBacklogSnapshot snapshot); /// /// Updates the health status for a data connection. /// /// The name of the connection. /// The connection health status. void UpdateConnectionHealth(string connectionName, ConnectionHealth health); /// /// Removes a connection from health tracking. /// /// The name of the connection. void RemoveConnection(string connectionName); /// /// Updates tag resolution metrics for a connection. /// /// The name of the connection. /// Total number of subscribed tags. /// Number of successfully resolved tags. void UpdateTagResolution(string connectionName, int totalSubscribed, int successfullyResolved); /// /// Updates the endpoint for a connection. /// /// The name of the connection. /// The connection endpoint. void UpdateConnectionEndpoint(string connectionName, string endpoint); /// /// Updates tag quality metrics for a connection. /// /// The name of the connection. /// Number of good quality tags. /// Number of bad quality tags. /// Number of uncertain quality tags. void UpdateTagQuality(string connectionName, int good, int bad, int uncertain); /// /// Sets the store-and-forward buffer depths for all categories. /// /// Dictionary mapping category names to their buffer depths. void SetStoreAndForwardDepths(IReadOnlyDictionary depths); /// /// Sets the counts of instances in each state. /// /// Number of deployed instances. /// Number of enabled instances. /// Number of disabled instances. void SetInstanceCounts(int deployed, int enabled, int disabled); /// /// Sets the count of parked messages. /// /// The number of parked messages. void SetParkedMessageCount(int count); /// /// Sets the age (seconds) of the oldest parked store-and-forward message for the /// next call; null when no rows are parked. /// Point-in-time (not reset on collect), refreshed by the parked-count poller in /// HealthReportSender. Default interface implementation is a no-op so /// existing test fakes continue to compile without per-fake updates. /// /// Age in seconds of the oldest parked row, or null if none are parked. void SetOldestParkedMessageAgeSeconds(double? ageSeconds) { // Default no-op so test fakes do not need to be updated. } /// /// Replace the latest cumulative /// site-event-log write-failure count (SQLite error, disk full, /// bounded-queue overflow drop) used by the next /// call. Refreshed periodically by the SiteEventLogFailureCountReporter /// hosted service. Point-in-time: the value is NOT reset on /// ; it carries forward until the next poller /// refresh. Default interface implementation is a no-op so existing test /// fakes continue to compile without per-fake updates. /// /// The cumulative failed-write count from ISiteEventLogger.FailedWriteCount. void SetSiteEventLogWriteFailures(long count) { // Default no-op so test fakes do not need to be updated. The real // SiteHealthCollector overrides this with the Interlocked.Exchange store. } /// /// Replace the latest LocalDb replication status (peer-session connectivity and /// unacked oplog backlog) used by the next call. /// Refreshed periodically by the LocalDbReplicationStatusReporter hosted /// service. Point-in-time: values are NOT reset on . /// /// /// Whether a sync session is currently running, or when there /// is no reading to give — which is the state of a node with replication UNCONFIGURED /// (register row 80). means "replication is configured on this /// node and the peer session is currently down", i.e. a genuine fault worth a badge; /// reporting that on a deliberately-unreplicated site reads as a fault that isn't one. /// /// /// Unacked oplog entries, or when unknown (failed poll) or not /// applicable (replication unconfigured). Pass null through unchanged: a failed poll /// rendered as 0 would report a broken pair as healthy. /// void SetLocalDbReplicationStatus(bool? connected, long? oplogBacklog) { // Default no-op so test fakes do not need to be updated. } /// /// Record whether this node spawned its SiteReconciliationActor at boot, for the /// StartupReconcilerActive field of every subsequent /// (deferred-work register row 73). /// /// /// Called ONCE at boot by the Host, which owns the spawn decision — this is a latched /// boot fact, not a polled gauge, so there is no reporter hosted service behind it. /// A collector that is never told (central's self-report, or any test host) leaves the /// field null, which reads as "not reported" rather than "reconciler absent". /// /// /// when the reconciler was created; when /// it was skipped because no IDeploymentConfigFetcher was available. /// void SetStartupReconcilerActive(bool active) { // Default no-op so test fakes do not need to be updated. } /// /// Replace the latest script-execution-scheduler gauges (queue depth, busy /// thread count, and age in seconds of the oldest in-flight script) used by /// the next call. Refreshed periodically by the /// ScriptSchedulerStatsReporter hosted service. Point-in-time: the /// values are NOT reset on . S2/UA5 — surfaces a /// saturated or stuck script-execution pool on the site health report. /// Default interface implementation is a no-op so existing test fakes continue /// to compile without per-fake updates. /// /// Script tasks waiting to run. /// Worker threads currently executing a script. /// Age (seconds) of the oldest in-flight script, or null when idle. /// /// WP3.1: worker threads the stuck-script watchdog has detached and replaced because /// their script wedged past its deadline plus grace, and which have not yet returned. /// A non-zero, non-draining value means script bodies are permanently blocking threads. /// void SetScriptSchedulerStats( int queueDepth, int busyThreads, double? oldestBusyAgeSeconds, int detachedThreads = 0) { // Default no-op so test fakes do not need to be updated. } /// /// WP2.6d (arch-review misc — site stream alarm-vs-attribute shared buffer): /// replace the latest cumulative count of alarm state changes dropped from /// SiteStreamManager's dedicated alarm publish queue, used by the next /// call. Refreshed periodically by the site-side /// SiteStreamAlarmDropReporter hosted service. Point-in-time: NOT reset on /// . Default interface implementation is a no-op so /// existing test fakes continue to compile without per-fake updates. /// /// The cumulative dropped-alarm count from SiteStreamManager.AlarmPublishDroppedCount. void SetSiteStreamAlarmDropCount(long count) { // Default no-op so test fakes do not need to be updated. The real // SiteHealthCollector overrides this with the Interlocked.Exchange store. } /// /// Sets the hostname of this node. /// /// The node hostname. void SetNodeHostname(string hostname); /// /// Sets the list of cluster nodes. /// /// The list of cluster node statuses. void SetClusterNodes(IReadOnlyList nodes); /// /// Sets whether this node is the active node in the cluster. /// /// True if this node is active, false otherwise. void SetActiveNode(bool isActive); /// /// Gets whether this node is the active node in the cluster. /// bool IsActiveNode { get; } /// /// Collects and returns a health report for a site. /// /// The site identifier. /// A health report for the specified site. SiteHealthReport CollectReport(string siteId); /// /// Atomically add back the given per-interval error /// counts into the collector's accumulators. Called by the report sender /// when transport delivery of a freshly-collected report fails, so the /// counts that already drained roll forward /// into the next report rather than being silently lost. Concurrent /// increments arriving between the failed Send and this restore are /// preserved — Interlocked.Add sums correctly with them. The /// default interface implementation is a no-op so existing test fakes /// (the only implementations outside ) /// continue to compile without per-fake updates; production callers see /// the real behaviour via the concrete class. /// /// Script error count to add back. /// Alarm evaluation error count to add back. /// Dead letter count to add back. /// Site audit write failure count to add back. /// Audit redaction failure count to add back. /// /// Interval-drained script/alarm run-shed count to add back (arch-review 2026-08-19 /// P8-1). Additive trailing parameter defaulting to 0 so existing callers keep /// compiling; DetachedScriptThreads/SiteStreamAlarmDropCount are /// point-in-time gauges, not drained on collect, so they need no restore path. /// void AddIntervalCounters( int scriptErrors, int alarmErrors, int deadLetters, int siteAuditWriteFailures, int auditRedactionFailures, int scriptRunShedCount = 0) { // Default no-op so test fakes do not need to be updated. The real // SiteHealthCollector overrides this with the Interlocked.Add restore. } }