c4186509f6
Interface now lives in Commons.Interfaces.Services; AuditLog no longer gets it transitively through Communication. Implementation stays in HealthMonitoring. Claude-Session: https://claude.ai/code/session_01GT67AEHd2Acv1YPwGfXEoV
92 lines
3.5 KiB
C#
92 lines
3.5 KiB
C#
using ZB.MOM.WW.ScadaBridge.Commons.Interfaces.Services;
|
|
using ZB.MOM.WW.ScadaBridge.Commons.Types.Enums;
|
|
using ZB.MOM.WW.ScadaBridge.HealthMonitoring;
|
|
|
|
namespace ZB.MOM.WW.ScadaBridge.SiteRuntime.Tests.TestSupport;
|
|
|
|
/// <summary>
|
|
/// Minimal <see cref="ISiteHealthCollector"/> whose only job is to expose the observable edge
|
|
/// "the Deployment Manager's boot-time config load has PROVABLY read storage". The manager calls
|
|
/// <see cref="SetInstanceCounts"/> unconditionally the moment that load finishes — including for
|
|
/// an empty site — so a non-zero <see cref="ReportCount"/> replaces a wall-clock sleep.
|
|
///
|
|
/// <para>
|
|
/// <b>Why every post-boot start-path test must gate on this (deferred register rows 83 + 78).</b>
|
|
/// A test that writes a <c>deployed_configurations</c> row BEFORE that read lands has its row
|
|
/// picked up by the boot load itself — so the test passes while proving the boot load works,
|
|
/// not the post-boot path (startup reconcile, sweep, enable) it claims to cover. A bare
|
|
/// <c>Task.Delay</c> only makes that race unlikely, not impossible: on a loaded machine the load
|
|
/// can still be in flight when the delay expires, and the test silently changes what it proves
|
|
/// instead of failing. Gating on the first instance-count report removes the race entirely.
|
|
/// </para>
|
|
/// </summary>
|
|
public sealed class DeploymentManagerStartupProbe : ISiteHealthCollector
|
|
{
|
|
private int _reports;
|
|
|
|
/// <summary>
|
|
/// Number of <see cref="SetInstanceCounts"/> calls seen. Greater than zero means the
|
|
/// boot-time config load has completed and read storage.
|
|
/// </summary>
|
|
public int ReportCount => Volatile.Read(ref _reports);
|
|
|
|
/// <inheritdoc />
|
|
public void SetInstanceCounts(int deployed, int enabled, int disabled) =>
|
|
Interlocked.Increment(ref _reports);
|
|
|
|
/// <inheritdoc />
|
|
public void IncrementScriptError() { }
|
|
|
|
/// <inheritdoc />
|
|
public void IncrementAlarmError() { }
|
|
|
|
/// <inheritdoc />
|
|
public void IncrementDeadLetter() { }
|
|
|
|
/// <inheritdoc />
|
|
public void IncrementSiteAuditWriteFailures() { }
|
|
|
|
/// <inheritdoc />
|
|
public void IncrementAuditRedactionFailure() { }
|
|
|
|
/// <inheritdoc />
|
|
public void UpdateSiteAuditBacklog(Commons.Types.SiteAuditBacklogSnapshot snapshot) { }
|
|
|
|
/// <inheritdoc />
|
|
public void UpdateConnectionHealth(string connectionName, ConnectionHealth health) { }
|
|
|
|
/// <inheritdoc />
|
|
public void RemoveConnection(string connectionName) { }
|
|
|
|
/// <inheritdoc />
|
|
public void UpdateTagResolution(string connectionName, int totalSubscribed, int successfullyResolved) { }
|
|
|
|
/// <inheritdoc />
|
|
public void UpdateConnectionEndpoint(string connectionName, string endpoint) { }
|
|
|
|
/// <inheritdoc />
|
|
public void UpdateTagQuality(string connectionName, int good, int bad, int uncertain) { }
|
|
|
|
/// <inheritdoc />
|
|
public void SetStoreAndForwardDepths(IReadOnlyDictionary<string, int> depths) { }
|
|
|
|
/// <inheritdoc />
|
|
public void SetParkedMessageCount(int count) { }
|
|
|
|
/// <inheritdoc />
|
|
public void SetNodeHostname(string hostname) { }
|
|
|
|
/// <inheritdoc />
|
|
public void SetClusterNodes(IReadOnlyList<Commons.Messages.Health.NodeStatus> nodes) { }
|
|
|
|
/// <inheritdoc />
|
|
public void SetActiveNode(bool isActive) { }
|
|
|
|
/// <inheritdoc />
|
|
public bool IsActiveNode => true;
|
|
|
|
/// <inheritdoc />
|
|
public Commons.Messages.Health.SiteHealthReport CollectReport(string siteId) =>
|
|
throw new NotSupportedException("Startup probe collects no report.");
|
|
}
|