feat(alarms): wire NativeAlarmAckRouter to DriverHostActor in host DI [H6e]
This commit is contained in:
@@ -139,6 +139,45 @@ public sealed class OtOpcUaServerHostedService : IHostedService, IAsyncDisposabl
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Wire the reverse-path native-alarm-ack router (H6e): a client Acknowledge of a NATIVE (driver-fed,
|
||||||
|
// e.g. Galaxy) Part 9 condition that passes the node manager's AlarmAck gate routes the acknowledge to
|
||||||
|
// the owning driver child. The node manager maps the inbound ack to an OpcUaServer-local NativeAlarmAck;
|
||||||
|
// HERE the host maps that to the Runtime DriverHostActor.RouteNativeAlarmAck (field-for-field) and Tells
|
||||||
|
// it into the local DriverHostActor, which Primary-gates + resolves the owning DriverInstanceActor. The
|
||||||
|
// mapping happens at this boundary so Runtime stays free of an OpcUaServer dependency. The Tell is
|
||||||
|
// fire-and-forget so the handler — which runs under the SDK's Lock — never blocks. The DriverHostActor
|
||||||
|
// ref is resolved LAZILY per ack (this StartAsync runs before the Akka DriverHostActor registers, so a
|
||||||
|
// one-shot resolve here would always miss); by ack time the registry has it, mirroring the node-write
|
||||||
|
// gateway below.
|
||||||
|
_server.SetNativeAlarmAckRouter(nativeAck =>
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (_actorRegistry.TryGet<DriverHostActorKey>(out var driverHost))
|
||||||
|
{
|
||||||
|
driverHost.Tell(new DriverHostActor.RouteNativeAlarmAck(
|
||||||
|
nativeAck.ConditionNodeId, nativeAck.Comment, nativeAck.OperatorUser));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// No driver host registered yet (admin-only node, or pre-registration race). The Part 9 ack
|
||||||
|
// already committed the local condition state; the missed routing surfaces as a non-applied
|
||||||
|
// upstream acknowledge, not a client-visible error.
|
||||||
|
_logger.LogWarning(
|
||||||
|
"OtOpcUaServerHostedService: native alarm ack for {ConditionNodeId} dropped — no DriverHostActor registered",
|
||||||
|
nativeAck.ConditionNodeId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
// The router runs under the SDK Lock on a server thread; a hiccup must not escape into the SDK's
|
||||||
|
// Call path. Log + drop — the client still gets Good for the condition-state change.
|
||||||
|
_logger.LogWarning(ex,
|
||||||
|
"OtOpcUaServerHostedService: failed to route native alarm ack for {ConditionNodeId}",
|
||||||
|
nativeAck.ConditionNodeId);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
// Wire the reverse-path inbound operator-write gateway: a client write to a writable equipment-tag
|
// Wire the reverse-path inbound operator-write gateway: a client write to a writable equipment-tag
|
||||||
// node that passes the node manager's WriteOperate gate routes the write to the owning driver child
|
// node that passes the node manager's WriteOperate gate routes the write to the owning driver child
|
||||||
// (RouteNodeWrite → NodeWriteResult) via the local DriverHostActor. The node manager calls the
|
// (RouteNodeWrite → NodeWriteResult) via the local DriverHostActor. The node manager calls the
|
||||||
@@ -185,6 +224,8 @@ public sealed class OtOpcUaServerHostedService : IHostedService, IAsyncDisposabl
|
|||||||
_deferredServiceLevel.SetInner(null);
|
_deferredServiceLevel.SetInner(null);
|
||||||
// Restore the Null write gateway so a late client write doesn't Ask a stopping DriverHostActor.
|
// Restore the Null write gateway so a late client write doesn't Ask a stopping DriverHostActor.
|
||||||
_server?.SetNodeWriteGateway(null);
|
_server?.SetNodeWriteGateway(null);
|
||||||
|
// Clear the native-alarm-ack router so a late ack doesn't Tell a stopping DriverHostActor.
|
||||||
|
_server?.SetNativeAlarmAckRouter(null);
|
||||||
// Restore the Null historian so a late HistoryRead doesn't hit a disposed read client.
|
// Restore the Null historian so a late HistoryRead doesn't hit a disposed read client.
|
||||||
_server?.SetHistorianDataSource(null);
|
_server?.SetHistorianDataSource(null);
|
||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
|
|||||||
@@ -37,6 +37,27 @@ public sealed class OtOpcUaSdkServer : StandardServer
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Wire the reverse-path router for inbound Part 9 Acknowledge of a NATIVE (driver-fed, e.g. Galaxy)
|
||||||
|
/// condition onto the created <see cref="OtOpcUaNodeManager"/>. The host calls this after start with a
|
||||||
|
/// non-blocking router that Tells a <c>DriverHostActor.RouteNativeAlarmAck</c> into the local
|
||||||
|
/// <c>DriverHostActor</c>, which (Primary-gated) routes the acknowledge to the owning driver child.
|
||||||
|
/// Native conditions are not owned by the scripted-alarm engine, so the node manager branches their
|
||||||
|
/// inbound Acknowledge to this seam instead of the scripted <see cref="SetAlarmCommandRouter"/> path.
|
||||||
|
/// Passing <c>null</c> clears it. No-op (returns <c>false</c>) when the node manager has not been
|
||||||
|
/// created yet, so the caller can detect a too-early call (mirrors <see cref="SetAlarmCommandRouter"/>).
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="router">The router invoked by the native condition's Acknowledge handler once the
|
||||||
|
/// <c>AlarmAck</c> gate passes; may be <c>null</c> to clear it.</param>
|
||||||
|
/// <returns><c>true</c> when the router was set on a live node manager; <c>false</c> when no node
|
||||||
|
/// manager exists yet.</returns>
|
||||||
|
public bool SetNativeAlarmAckRouter(Action<NativeAlarmAck>? router)
|
||||||
|
{
|
||||||
|
if (_otOpcUaNodeManager is null) return false;
|
||||||
|
_otOpcUaNodeManager.NativeAlarmAckRouter = router;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Wire the reverse-path gateway for inbound operator writes to writable equipment-tag nodes onto the
|
/// Wire the reverse-path gateway for inbound operator writes to writable equipment-tag nodes onto the
|
||||||
/// created <see cref="OtOpcUaNodeManager"/>. The host calls this after start with an
|
/// created <see cref="OtOpcUaNodeManager"/>. The host calls this after start with an
|
||||||
|
|||||||
Reference in New Issue
Block a user