feat(runtime): ServerHistorian HistoryRead parallelism/limiter/deadline knobs + node-manager wiring (03/S3)

This commit is contained in:
Joseph Doherty
2026-07-13 12:03:27 -04:00
parent d5c6609cdf
commit 304442dba4
5 changed files with 117 additions and 1 deletions
@@ -197,6 +197,30 @@ public sealed class OtOpcUaNodeManager : CustomNodeManager2
/// </summary>
public int MaxTieClusterOverfetch { get; set; } = 65536;
/// <summary>
/// Maximum historized nodes served concurrently within one HistoryRead batch (arch-review 03/S3).
/// Mirrors <c>ServerHistorianOptions.HistoryReadBatchParallelism</c>; the Host sets it at
/// <c>StartAsync</c>. <c>≤ 1</c> falls back to sequential serving. The default (4) survives when the
/// ServerHistorian section is absent.
/// </summary>
public int HistoryReadBatchParallelism { get; set; } = 4;
/// <summary>
/// Process-wide cap on concurrently-served HistoryRead batches (arch-review 03/S3). A batch that
/// cannot acquire a slot within its (bounded) wait budget fast-fails every handle with
/// <c>BadTooManyOperations</c>. Mirrors <c>ServerHistorianOptions.MaxConcurrentHistoryReadBatches</c>;
/// the Host sets it at <c>StartAsync</c>. The default (16) survives when the section is absent.
/// </summary>
public int MaxConcurrentHistoryReadBatches { get; set; } = 16;
/// <summary>
/// Per-request wall-clock deadline for a HistoryRead batch (arch-review 03/S3). A node still in
/// flight at the deadline surfaces <c>BadTimeout</c>. Non-positive = unbounded. Mirrors
/// <c>ServerHistorianOptions.HistoryReadDeadline</c>; the Host sets it at <c>StartAsync</c>. The
/// default (60 s) survives when the section is absent.
/// </summary>
public TimeSpan HistoryReadDeadline { get; set; } = TimeSpan.FromSeconds(60);
private volatile IHistoryContinuationStore _historyContinuationStore = new SessionHistoryContinuationStore();
/// <summary>