fix(opcua): RunContinuationsAsynchronously so revert never re-enters the write Lock
This commit is contained in:
@@ -638,7 +638,10 @@ public sealed class OtOpcUaNodeManager : CustomNodeManager2
|
||||
|
||||
// Fire-and-forget — MUST NOT block under Lock. On a FAILED outcome, compare-and-revert (off-Lock
|
||||
// continuation). A faulted/cancelled WriteAsync is treated as a failure so the optimistic value never
|
||||
// sticks when the route never resolved a real outcome.
|
||||
// sticks when the route never resolved a real outcome. RunContinuationsAsynchronously guarantees the
|
||||
// revert never runs inline on the SDK write thread (the gateway can return a synchronously-completed
|
||||
// task — e.g. its boot-window "no DriverHostActor yet" branch), so RevertOptimisticWriteIfNeeded never
|
||||
// re-enters lock (Lock) while CustomNodeManager2.Write still holds it.
|
||||
_ = gateway.WriteAsync(nodeKey, optimisticValue, CancellationToken.None)
|
||||
.ContinueWith(
|
||||
t =>
|
||||
@@ -646,7 +649,7 @@ public sealed class OtOpcUaNodeManager : CustomNodeManager2
|
||||
var outcome = t.IsCompletedSuccessfully ? t.Result : new NodeWriteOutcome(false, "write dispatch faulted");
|
||||
RevertOptimisticWriteIfNeeded(nodeKey, outcome, optimisticValue, priorValue, priorStatus);
|
||||
},
|
||||
CancellationToken.None, TaskContinuationOptions.None, TaskScheduler.Default);
|
||||
CancellationToken.None, TaskContinuationOptions.RunContinuationsAsynchronously, TaskScheduler.Default);
|
||||
|
||||
return ServiceResult.Good;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user