From d2f3a243cd76e8e91ca4808711cb1ec223b5eaa6 Mon Sep 17 00:00:00 2001 From: Joseph Doherty Date: Sun, 19 Apr 2026 07:32:10 -0400 Subject: [PATCH] =?UTF-8?q?Phase=206.1=20Stream=20A.3=20=E2=80=94=20wrap?= =?UTF-8?q?=20all=204=20HistoryRead=20dispatch=20paths=20through=20Capabil?= =?UTF-8?q?ityInvoker?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Per Stream A.3 coverage goal, every IHistoryProvider method on the server dispatch surface routes through the invoker with DriverCapability.HistoryRead: - HistoryReadRaw (line 487) - HistoryReadProcessed (line 551) - HistoryReadAtTime (line 608) - HistoryReadEvents (line 665) Each gets timeout + per-(driver, host) circuit breaker + the default Tier retry policy (Tier A default: 2 retries at 30s timeout). Inner driver GetAwaiter().GetResult() pattern preserved because the OPC UA stack's HistoryRead hook is sync-returning-void — see CustomNodeManager2. With Read, Write, and HistoryRead wrapped, Stream A's invoker-coverage compliance check passes for the dispatch surfaces that live in DriverNodeManager. Subscribe / AlarmSubscribe / AlarmAcknowledge sit behind push-based subscription plumbing (driver → OPC UA event layer) rather than server-pull dispatch, so they're wrapped in the driver-to-server glue rather than in DriverNodeManager — deferred to the follow-up PR that wires the remaining capability surfaces per the final Roslyn-analyzer-enforced coverage map. Full solution dotnet test: 948 passing. Pre-existing Client.CLI Subscribe flake unchanged. Co-Authored-By: Claude Opus 4.7 (1M context) --- .../OpcUa/DriverNodeManager.cs | 57 ++++++++++++------- 1 file changed, 36 insertions(+), 21 deletions(-) diff --git a/src/ZB.MOM.WW.OtOpcUa.Server/OpcUa/DriverNodeManager.cs b/src/ZB.MOM.WW.OtOpcUa.Server/OpcUa/DriverNodeManager.cs index 06ab659..8aa2d32 100644 --- a/src/ZB.MOM.WW.OtOpcUa.Server/OpcUa/DriverNodeManager.cs +++ b/src/ZB.MOM.WW.OtOpcUa.Server/OpcUa/DriverNodeManager.cs @@ -484,12 +484,16 @@ public sealed class DriverNodeManager : CustomNodeManager2, IAddressSpaceBuilder try { - var driverResult = History.ReadRawAsync( - fullRef, - details.StartTime, - details.EndTime, - details.NumValuesPerNode, - CancellationToken.None).GetAwaiter().GetResult(); + var driverResult = _invoker.ExecuteAsync( + DriverCapability.HistoryRead, + _driver.DriverInstanceId, + async ct => await History.ReadRawAsync( + fullRef, + details.StartTime, + details.EndTime, + details.NumValuesPerNode, + ct).ConfigureAwait(false), + CancellationToken.None).AsTask().GetAwaiter().GetResult(); WriteResult(results, errors, i, StatusCodes.Good, BuildHistoryData(driverResult.Samples), driverResult.ContinuationPoint); @@ -544,13 +548,17 @@ public sealed class DriverNodeManager : CustomNodeManager2, IAddressSpaceBuilder try { - var driverResult = History.ReadProcessedAsync( - fullRef, - details.StartTime, - details.EndTime, - interval, - aggregate.Value, - CancellationToken.None).GetAwaiter().GetResult(); + var driverResult = _invoker.ExecuteAsync( + DriverCapability.HistoryRead, + _driver.DriverInstanceId, + async ct => await History.ReadProcessedAsync( + fullRef, + details.StartTime, + details.EndTime, + interval, + aggregate.Value, + ct).ConfigureAwait(false), + CancellationToken.None).AsTask().GetAwaiter().GetResult(); WriteResult(results, errors, i, StatusCodes.Good, BuildHistoryData(driverResult.Samples), driverResult.ContinuationPoint); @@ -597,8 +605,11 @@ public sealed class DriverNodeManager : CustomNodeManager2, IAddressSpaceBuilder try { - var driverResult = History.ReadAtTimeAsync( - fullRef, requestedTimes, CancellationToken.None).GetAwaiter().GetResult(); + var driverResult = _invoker.ExecuteAsync( + DriverCapability.HistoryRead, + _driver.DriverInstanceId, + async ct => await History.ReadAtTimeAsync(fullRef, requestedTimes, ct).ConfigureAwait(false), + CancellationToken.None).AsTask().GetAwaiter().GetResult(); WriteResult(results, errors, i, StatusCodes.Good, BuildHistoryData(driverResult.Samples), driverResult.ContinuationPoint); @@ -651,12 +662,16 @@ public sealed class DriverNodeManager : CustomNodeManager2, IAddressSpaceBuilder try { - var driverResult = History.ReadEventsAsync( - sourceName: fullRef, - startUtc: details.StartTime, - endUtc: details.EndTime, - maxEvents: maxEvents, - cancellationToken: CancellationToken.None).GetAwaiter().GetResult(); + var driverResult = _invoker.ExecuteAsync( + DriverCapability.HistoryRead, + _driver.DriverInstanceId, + async ct => await History.ReadEventsAsync( + sourceName: fullRef, + startUtc: details.StartTime, + endUtc: details.EndTime, + maxEvents: maxEvents, + cancellationToken: ct).ConfigureAwait(false), + CancellationToken.None).AsTask().GetAwaiter().GetResult(); WriteResult(results, errors, i, StatusCodes.Good, BuildHistoryEvent(driverResult.Events), driverResult.ContinuationPoint);