fix(r2-06): wire AddValidatedOptions<ServerHistorianOptions> + alarm-only-mode startup warning in Program.cs (06/S-11)

This commit is contained in:
Joseph Doherty
2026-07-13 09:55:25 -04:00
parent 5369994e57
commit e748f929c8
2 changed files with 22 additions and 1 deletions
@@ -35,7 +35,7 @@
{
"id": "T5",
"subject": "Wiring: AddValidatedOptions<ServerHistorianOptions, ServerHistorianOptionsValidator> in Program.cs hasDriver block + OptionsValidationException wiring test + residual alarm-only-mode startup warning",
"status": "pending",
"status": "completed",
"blockedBy": [
"T4"
]
@@ -117,11 +117,32 @@ if (hasDriver)
// the read-side GatewayHistorianDataSource to stop owning + disposing its client (regressing the read
// cutover), and a second channel to a co-located sidecar is cheap (the gateway pools the historian
// sessions server-side).
// Fail-fast startup validation for the ServerHistorian section (archreview 06/S-11). A
// provably-crashing config — an enabled historian (or an enabled AlarmHistorian, which sources its
// gateway connection from THIS section) with an empty/malformed Endpoint — now fails host start with
// a named OptionsValidationException instead of a raw UriFormatException crash-loop out of the gateway
// client factory. Driver-block-only (mirrors OpcUaApplicationHostOptionsValidator below): admin-only
// nodes never build the historian singletons, so they must not be failed by a section they never
// consume. ApiKey/MaxTieClusterOverfetch stay warnings (they degrade, not crash) — see Validate().
builder.Services.AddValidatedOptions<ServerHistorianOptions, ServerHistorianOptionsValidator>(
builder.Configuration, ServerHistorianOptions.SectionName);
var serverHistorianOptions = builder.Configuration
.GetSection(ServerHistorianOptions.SectionName).Get<ServerHistorianOptions>()
?? new ServerHistorianOptions();
foreach (var warning in serverHistorianOptions.Validate())
Log.Warning("ServerHistorian misconfiguration detected at startup: {Warning}", warning);
// Residual "unusual but valid" corner (archreview 06/S-11): an alarm-history-only deployment
// (AlarmHistorian:Enabled=true while ServerHistorian:Enabled=false) legitimately sources its gateway
// connection from the disabled ServerHistorian section. That is allowed (the endpoint was already
// validated above), but log it so the mode is not a silent surprise: HistoryReads stay GoodNoData,
// and a wrong endpoint/key surfaces only as SQLite store-and-forward retry/dead-letter growth.
if (builder.Configuration.GetValue<bool>("AlarmHistorian:Enabled") && !serverHistorianOptions.Enabled)
Log.Warning(
"AlarmHistorian is enabled but ServerHistorian is disabled — the alarm-history sink is sourcing its " +
"gateway connection (endpoint/key/TLS) from the disabled ServerHistorian section; HistoryReads stay GoodNoData.");
builder.Services.AddAlarmHistorian(
builder.Configuration,
(_, sp) => GatewayHistorian.CreateAlarmWriter(serverHistorianOptions, sp));