perf(dcl): batch subscribe/read/write seam, bounded reconnect, sharded subscriptions

This commit is contained in:
Joseph Doherty
2026-08-14 21:14:04 -04:00
parent ee193cd2bb
commit d15c5f02ea
25 changed files with 3131 additions and 324 deletions
@@ -8,9 +8,70 @@ public class DataConnectionOptions
/// <summary>Fixed interval between reconnect attempts after disconnect.</summary>
public TimeSpan ReconnectInterval { get; set; } = TimeSpan.FromSeconds(5);
/// <summary>Interval for retrying failed tag path resolution.</summary>
/// <summary>
/// Floor interval for retrying failed tag path resolution. The retry backs off
/// exponentially (doubling per fully-failed round) up to
/// <see cref="TagResolutionRetryMaxInterval"/>, and resets to this floor as soon as
/// any tag resolves or the connection reconnects.
/// </summary>
public TimeSpan TagResolutionRetryInterval { get; set; } = TimeSpan.FromSeconds(10);
/// <summary>
/// Ceiling for the exponential tag-resolution retry backoff. A dead device with
/// thousands of unresolved tags would otherwise probe forever at full width every
/// <see cref="TagResolutionRetryInterval"/>.
/// </summary>
public TimeSpan TagResolutionRetryMaxInterval { get; set; } = TimeSpan.FromMinutes(5);
/// <summary>
/// Number of tags per adapter subscribe round trip on the batch subscribe path
/// (initial subscribe, reconnect re-subscribe, tag-resolution probes).
/// </summary>
public int SubscribeBatchSize { get; set; } = 500;
/// <summary>
/// Delay inserted BETWEEN reconnect re-subscribe chunks so a site-wide reconnect
/// paces the device instead of issuing one task per tag in a tight loop. Not applied
/// on the instance-driven subscribe path — the Deployment Manager already staggers
/// instance startup there, and double-staggering would only slow failover.
/// </summary>
public TimeSpan SubscribeBatchDelay { get; set; } = TimeSpan.FromMilliseconds(50);
/// <summary>
/// Number of tags per seed-read chunk. Moderate on purpose: chunking plus the
/// per-chunk <see cref="SeedReadTimeout"/> answers the "some gateways time out on a
/// large batch" caveat that originally motivated per-tag seed reads.
/// </summary>
public int SeedReadBatchSize { get; set; } = 250;
/// <summary>Maximum seed-read chunks in flight concurrently.</summary>
public int SeedReadMaxParallelism { get; set; } = 4;
/// <summary>
/// Wall-clock deadline for the WHOLE seed (all chunks and all retry rounds). On
/// expiry the remaining tags are logged and stay Uncertain until a change
/// notification arrives — the same outcome as exhausting
/// <see cref="SeedReadMaxAttempts"/>.
/// </summary>
public TimeSpan SeedOverallTimeout { get; set; } = TimeSpan.FromSeconds(120);
/// <summary>
/// Coalescing window for pushing tag-quality counters to the health collector.
/// Counter math stays per message; only the collector push is deferred, and only
/// when a genuine quality transition occurred. Health reports poll at 30s, so a
/// short window loses nothing. Disconnect / unsubscribe / reconnect-reset flushes
/// stay synchronous.
/// </summary>
public TimeSpan QualityFlushInterval { get; set; } = TimeSpan.FromSeconds(1);
/// <summary>
/// Maximum in-flight supervisory advise commands when the MxGateway adapter has no
/// write-user context. The gateway worker has no BULK supervisory advise, so the
/// client pipelines per-item advises after one bulk AddItem instead of issuing them
/// serially.
/// </summary>
public int MxSupervisoryAdviseParallelism { get; set; } = 16;
/// <summary>Timeout for synchronous write operations to devices.</summary>
public TimeSpan WriteTimeout { get; set; } = TimeSpan.FromSeconds(30);