feat(historian-gateway): wire ContinuousHistorizationRecorder into DI + hosted lifecycle + meters
Bind ContinuousHistorizationOptions (Enabled/OutboxPath/CommitMode/ CommitIntervalMs/DrainBatchSize/DrainIntervalSeconds/Capacity/backoff) with a warn-only Validate(); gated on Enabled AND the ServerHistorian gateway being configured, the Host registers the durable FasterLogHistorizationOutbox (container -disposed) + a gateway-backed GatewayHistorianValueWriter, and binds outbox depth/dropped observable gauges on the central scraped meter. WithOtOpcUaRuntimeActors spawns the recorder (over the same dependency-mux ref) when the options + writer + outbox resolve, registering ContinuousHistorizationRecorderKey. Spawned with an EMPTY historized-ref set: the deployed address space builds later, so ref population is a documented follow-on (a later SetHistorizedRefs feed) — T18 wires the actor + outbox + writer + meters; the ref feed is the known remaining gap. Claude-Session: https://claude.ai/code/session_012SDSQ3AcaXqPcBtDESBRii
This commit is contained in:
@@ -23,6 +23,8 @@ using ZB.MOM.WW.OtOpcUa.Host.Logging;
|
||||
using ZB.MOM.WW.OtOpcUa.Host.Observability;
|
||||
using ZB.MOM.WW.OtOpcUa.Host.OpcUa;
|
||||
using ZB.MOM.WW.OtOpcUa.Driver.Historian.Gateway;
|
||||
using ZB.MOM.WW.OtOpcUa.Driver.Historian.Gateway.Recorder;
|
||||
using ZB.MOM.WW.OtOpcUa.Core.Abstractions.Historian;
|
||||
using ZB.MOM.WW.OtOpcUa.OpcUaServer;
|
||||
using ZB.MOM.WW.OtOpcUa.Runtime.Historian;
|
||||
using ZB.MOM.WW.OtOpcUa.Runtime.Scripting;
|
||||
@@ -124,6 +126,49 @@ if (hasDriver)
|
||||
builder.Configuration,
|
||||
(opts, sp) => GatewayHistorian.CreateDataSource(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
|
||||
// section (this section carries only the recorder + outbox knobs). When both are on, register the durable
|
||||
// crash-safe outbox + the gateway-backed live-value writer here; WithOtOpcUaRuntimeActors (below) spawns
|
||||
// the recorder actor itself, gated on the same options.
|
||||
var continuousHistorizationOptions = builder.Configuration
|
||||
.GetSection(ContinuousHistorizationOptions.SectionName).Get<ContinuousHistorizationOptions>()
|
||||
?? new ContinuousHistorizationOptions();
|
||||
foreach (var warning in continuousHistorizationOptions.Validate())
|
||||
Log.Warning("ContinuousHistorization misconfiguration detected at startup: {Warning}", warning);
|
||||
if (serverHistorianOptions.Enabled && continuousHistorizationOptions.Enabled)
|
||||
{
|
||||
// Register the bound options so WithOtOpcUaRuntimeActors can gate the recorder spawn on Enabled.
|
||||
builder.Services.AddSingleton(continuousHistorizationOptions);
|
||||
|
||||
// Durable, crash-safe FasterLog outbox (the historization crash boundary). Built via the factory so
|
||||
// the container OWNS disposal (FasterLogHistorizationOutbox is IDisposable). Binding the observable
|
||||
// outbox depth/dropped gauges here (once, on first resolution) keeps the live instance behind them.
|
||||
builder.Services.AddSingleton<IHistorizationOutbox>(_ =>
|
||||
{
|
||||
var commitMode = Enum.TryParse<HistorizationCommitMode>(
|
||||
continuousHistorizationOptions.CommitMode, ignoreCase: true, out var parsedMode)
|
||||
? parsedMode
|
||||
: HistorizationCommitMode.PerEntry;
|
||||
var outbox = new FasterLogHistorizationOutbox(
|
||||
continuousHistorizationOptions.OutboxPath,
|
||||
commitMode,
|
||||
continuousHistorizationOptions.CommitIntervalMs,
|
||||
continuousHistorizationOptions.Capacity);
|
||||
ContinuousHistorizationMetrics.BindOutbox(outbox);
|
||||
return outbox;
|
||||
});
|
||||
|
||||
// Gateway-backed live-value writer over its OWN gRPC channel to the same single gateway (a second
|
||||
// channel to a co-located sidecar is cheap — the gateway pools the historian sessions server-side).
|
||||
builder.Services.AddSingleton<IHistorianValueWriter>(sp =>
|
||||
new GatewayHistorianValueWriter(
|
||||
HistorianGatewayClientAdapter.Create(
|
||||
serverHistorianOptions, sp.GetRequiredService<ILoggerFactory>()),
|
||||
sp.GetRequiredService<ILogger<GatewayHistorianValueWriter>>()));
|
||||
}
|
||||
|
||||
// Bind every cross-platform driver factory before AddAkka resolves IDriverFactory — replaces
|
||||
// the F7-default NullDriverFactory with a real DriverFactoryRegistryAdapter so DriverHostActor
|
||||
// can materialise real IDriver instances on deploy.
|
||||
|
||||
Reference in New Issue
Block a user