namespace ZB.MOM.WW.ScadaBridge.AuditLog.Central;
///
/// Tuning knobs for the central singleton.
/// Defaults mirror the M6 Bundle B brief: pull every 5 minutes per site, 256 rows per
/// batch, declare a site "stalled" after two consecutive pull cycles return non-empty
/// AND MoreAvailable=true (the backlog is not draining).
///
///
///
/// Per the M6 plan the reconciliation actor is the fallback when push telemetry is
/// lost; it is intentionally low-frequency. Lowering
/// in production trades MS SQL load for
/// fresher self-healing — keep the default unless a deployment can prove the extra
/// load is acceptable.
///
///
/// = 2 because a single non-draining
/// cycle can happen on a surge (e.g. a backed-up site replays its hot queue); the
/// stalled signal should only fire when the backlog persists across cycles, which is
/// the symptom the central health surface is asking us to detect.
///
///
public sealed class SiteAuditReconciliationOptions
{
///
/// Period of the reconciliation tick. Each tick visits every known site once.
///
public int ReconciliationIntervalSeconds { get; set; } = 300;
///
/// Test-only override for finer control over the tick cadence than
/// whole-second resolution allows. When non-null, takes precedence over
/// AND bypasses the
/// minimum clamp (so tests can use
/// millisecond cadences). Production config exposes
/// only and never sets this
/// knob — but because the options class is Bind-ed wholesale, a
/// config value at AuditLog:Reconciliation:ReconciliationIntervalOverride
/// WOULD bind if present; operators must not set it.
///
public TimeSpan? ReconciliationIntervalOverride { get; set; }
///
/// Minimum interval the config-bound
/// can resolve to. Clamps a misconfigured ReconciliationIntervalSeconds: 0
/// (or a negative value) away from , which would make
/// Akka's ScheduleTellRepeatedlyCancelable spin. The test-only
/// bypasses this clamp so unit tests
/// can still drop the cadence to milliseconds.
///
private static readonly TimeSpan MinConfiguredInterval = TimeSpan.FromSeconds(1);
///
/// Resolves the effective tick interval, honouring the test override when
/// set. Falls back to , clamped to at
/// least so a zero/negative config value can
/// never yield (which would spin the scheduler).
///
public TimeSpan ReconciliationInterval
{
get
{
if (ReconciliationIntervalOverride is { } overrideValue)
{
return overrideValue;
}
var resolved = TimeSpan.FromSeconds(ReconciliationIntervalSeconds);
return resolved < MinConfiguredInterval ? MinConfiguredInterval : resolved;
}
}
///
/// Maximum number of
/// rows requested in a single PullAuditEvents RPC call.
///
public int BatchSize { get; set; } = 256;
///
/// Number of consecutive non-draining cycles (events returned AND
/// MoreAvailable=true) that must accumulate for a site before the actor
/// publishes SiteAuditTelemetryStalledChanged(Stalled: true) on the
/// EventStream.
///
public int StalledAfterNonDrainingCycles { get; set; } = 2;
}