fix: propagate SDK request cancellation to historian calls
This commit is contained in:
@@ -5577,7 +5577,7 @@ public sealed class OtOpcUaNodeManager : CustomNodeManager2
|
||||
nodesToProcess = AuthorizeHistoryRead(context, nodesToProcess, results, errors);
|
||||
WithHistoryReadBatchLimiter(nodesToProcess, results, errors, () =>
|
||||
{
|
||||
using var deadline = CreateDeadline();
|
||||
using var deadline = CreateDeadline(context);
|
||||
var ct = deadline?.Token ?? CancellationToken.None;
|
||||
var work = new List<Func<Task>>(nodesToProcess.Count);
|
||||
foreach (var handle in nodesToProcess)
|
||||
@@ -5632,7 +5632,7 @@ public sealed class OtOpcUaNodeManager : CustomNodeManager2
|
||||
var served = AdvertisedAggregateFunctions.ServedBy(HistorianDataSource);
|
||||
WithHistoryReadBatchLimiter(nodesToProcess, results, errors, () =>
|
||||
{
|
||||
using var deadline = CreateDeadline();
|
||||
using var deadline = CreateDeadline(context);
|
||||
var ct = deadline?.Token ?? CancellationToken.None;
|
||||
var work = new List<Func<Task>>(nodesToProcess.Count);
|
||||
foreach (var handle in nodesToProcess)
|
||||
@@ -5691,7 +5691,7 @@ public sealed class OtOpcUaNodeManager : CustomNodeManager2
|
||||
nodesToProcess = AuthorizeHistoryRead(context, nodesToProcess, results, errors);
|
||||
WithHistoryReadBatchLimiter(nodesToProcess, results, errors, () =>
|
||||
{
|
||||
using var deadline = CreateDeadline();
|
||||
using var deadline = CreateDeadline(context);
|
||||
var ct = deadline?.Token ?? CancellationToken.None;
|
||||
var work = new List<Func<Task>>(nodesToProcess.Count);
|
||||
foreach (var handle in nodesToProcess)
|
||||
@@ -5781,7 +5781,7 @@ public sealed class OtOpcUaNodeManager : CustomNodeManager2
|
||||
nodesToProcess = AuthorizeHistoryRead(context, nodesToProcess, results, errors);
|
||||
WithHistoryReadBatchLimiter(nodesToProcess, results, errors, () =>
|
||||
{
|
||||
using var deadline = CreateDeadline();
|
||||
using var deadline = CreateDeadline(context);
|
||||
var ct = deadline?.Token ?? CancellationToken.None;
|
||||
var work = new List<Func<Task>>(nodesToProcess.Count);
|
||||
foreach (var handle in nodesToProcess)
|
||||
@@ -6381,7 +6381,7 @@ public sealed class OtOpcUaNodeManager : CustomNodeManager2
|
||||
|
||||
WithHistoryReadBatchLimiter(planned.Select(p => p.Handle).ToList(), results, errors, () =>
|
||||
{
|
||||
using var deadline = CreateDeadline();
|
||||
using var deadline = CreateDeadline(context);
|
||||
var ct = deadline?.Token ?? CancellationToken.None;
|
||||
var work = new List<Func<Task>>(planned.Count);
|
||||
foreach (var (handle, tagname, operation) in planned)
|
||||
@@ -6753,16 +6753,19 @@ public sealed class OtOpcUaNodeManager : CustomNodeManager2
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create the per-request deadline source for a HistoryRead arm (arch-review 03/S3): a
|
||||
/// <see cref="CancellationTokenSource"/> that fires after <see cref="HistoryReadDeadline"/>, so a
|
||||
/// single request can never hold an SDK request thread longer than the deadline regardless of node
|
||||
/// count. Returns <c>null</c> when the deadline is non-positive (unbounded — the arm then passes
|
||||
/// <see cref="CancellationToken.None"/>), matching the <c>ServerHistorianOptions</c> warning.
|
||||
/// </summary>
|
||||
/// <returns>The deadline source, or <c>null</c> for an unbounded (non-positive) deadline.</returns>
|
||||
private CancellationTokenSource? CreateDeadline() =>
|
||||
HistoryReadDeadline > TimeSpan.Zero ? new CancellationTokenSource(HistoryReadDeadline) : null;
|
||||
/// <summary>Link the SDK request lifetime to the application's per-batch history deadline.</summary>
|
||||
/// <param name="context">The request's server context.</param>
|
||||
/// <returns>The linked deadline source, or null when neither request nor application can cancel.</returns>
|
||||
private CancellationTokenSource? CreateDeadline(ServerSystemContext context)
|
||||
{
|
||||
var request = context.OperationContext?.CancellationToken ?? CancellationToken.None;
|
||||
if (!request.CanBeCanceled && HistoryReadDeadline <= TimeSpan.Zero) return null;
|
||||
var deadline = request.CanBeCanceled
|
||||
? CancellationTokenSource.CreateLinkedTokenSource(request)
|
||||
: new CancellationTokenSource();
|
||||
if (HistoryReadDeadline > TimeSpan.Zero) deadline.CancelAfter(HistoryReadDeadline);
|
||||
return deadline;
|
||||
}
|
||||
|
||||
/// <summary>Awaits one work item under a semaphore permit, releasing it when the item completes.</summary>
|
||||
/// <param name="gate">The concurrency-limiting semaphore.</param>
|
||||
|
||||
Reference in New Issue
Block a user