fix(historian-gateway): wire dormant GatewayTagProvisioner + provisioning observability/docs
PR #423 shipped GatewayTagProvisioner + unit tests but never registered it in DI nor passed it into the AddressSpaceApplier, so deploying historized tags used the no-op NullHistorianProvisioning and never called the gateway's EnsureTags (confirmed live on wonder-app-vd03: zero EnsureTags calls on a historized deploy). Addresses HISTORIAN-GATEWAY-INTEGRATION-ISSUES.md. Issue 1 (wire provisioner): - Runtime: AddHistorianProvisioning extension (gated on ServerHistorian:Enabled, mirrors AddServerHistorian) + NullHistorianProvisioning TryAdd default in AddOtOpcUaRuntime; WithOtOpcUaRuntimeActors resolves IHistorianProvisioning and passes it into the applier. - Gateway driver: GatewayHistorian.CreateProvisioner factory (mirrors CreateDataSource). - Host: Program.cs calls AddHistorianProvisioning after AddServerHistorian. - Tests: AddHistorianProvisioningTests (config-gated registration + the register->resolve->applier->EnsureTags chain). Issue 2 (observability): AddressSpaceApplier logs the provisioning tally on every successful dispatch (was gated behind Failed/Skipped > 0), including dispatched=N so a dispatched=N/requested=0 line flags the dormant no-op. +2 tests. Issue 3 (30s HistoryRead on unprovisioned tags): root coupling fixed by Issue 1; documented the CallTimeout knob + coupling. Default left at 30s pending the multi-data-point investigation the issue requests (lowering risks truncating legitimate large reads). Issue 4 (docs): docs/Historian.md gains a "Tag auto-provisioning (EnsureTags)" section and CLAUDE.md a wiring/gating note (both stress ServerHistorian:Enabled). Sibling scadaproj/CLAUDE.md carries no false claim -> unchanged. Pre-existing Serilog observation: anchor CWD to AppContext.BaseDirectory before AddZbSerilog so the relative file sink stops landing in C:\Windows\System32 under the Windows-service CWD. Builds 0-error; Runtime.Tests 355, OpcUaServer.Tests 329, Gateway.Tests 99 (+4 live-skipped) all green.
This commit is contained in:
@@ -72,6 +72,16 @@ if (roleSuffix is not null)
|
||||
builder.Configuration.AddCommandLine(args);
|
||||
}
|
||||
|
||||
// Anchor the process working directory to the install directory (AppContext.BaseDirectory) so every
|
||||
// relative runtime path resolves under the install dir rather than the service's startup CWD. A Windows
|
||||
// service starts with CWD=C:\Windows\System32, which otherwise scattered the Serilog rolling-file sink
|
||||
// (appsettings "logs/otopcua-.log") into System32 and made on-box diagnosis awkward; the same anchor also
|
||||
// roots the script log, the historization outbox, and any other relative artifact path. Done AFTER
|
||||
// WebApplication.CreateBuilder (which has already resolved the content root + appsettings.json) and BEFORE
|
||||
// AddZbSerilog (which instantiates the file sink), so only path resolution moves — config loading is
|
||||
// untouched. UseWindowsService already roots the content root at the base dir, so this only affects sinks.
|
||||
Directory.SetCurrentDirectory(AppContext.BaseDirectory);
|
||||
|
||||
// Serilog — shared ZB.MOM.WW.Telemetry bootstrap. Sinks (Console + rolling daily file)
|
||||
// now live in appsettings.json (ReadFrom.Configuration); AddZbSerilog layers in the
|
||||
// shared NodeHostname / TraceContext / Redaction enrichers and trace correlation.
|
||||
@@ -125,6 +135,17 @@ if (hasDriver)
|
||||
builder.Configuration,
|
||||
(opts, sp) => GatewayHistorian.CreateDataSource(opts, sp));
|
||||
|
||||
// Config-gated historian tag provisioning. When the ServerHistorian section is enabled this registers the
|
||||
// gateway-backed GatewayTagProvisioner (overriding the NullHistorianProvisioning default) so that deploying
|
||||
// a historized tag auto-ensures it in the historian via the gateway's EnsureTags. The AddressSpaceApplier
|
||||
// (constructed in WithOtOpcUaRuntimeActors) resolves IHistorianProvisioning and fires a non-blocking
|
||||
// EnsureTagsAsync for added historized tags on every deploy; without this registration the applier falls
|
||||
// back to the no-op NullHistorianProvisioning and provisioning never reaches the gateway. Gated on the SAME
|
||||
// ServerHistorian:Enabled flag as the read path — both target the same single gateway.
|
||||
builder.Services.AddHistorianProvisioning(
|
||||
builder.Configuration,
|
||||
(opts, sp) => GatewayHistorian.CreateProvisioner(opts, sp));
|
||||
|
||||
// Continuous historization of driver (non-Galaxy) tag values. Gated on ContinuousHistorization:Enabled
|
||||
// AND the ServerHistorian gateway being configured: the recorder drains driver-tag live values to the
|
||||
// SAME single gateway's WriteLiveValues SQL path, sourcing endpoint/key/TLS from the ServerHistorian
|
||||
|
||||
Reference in New Issue
Block a user