feat(otopcua): make FixedTree re-discovery per-pass timeout injectable (follow-up A)
This commit is contained in:
@@ -38,6 +38,10 @@ public sealed class DriverInstanceActor : ReceiveActor, IWithTimers
|
||||
/// <summary>Default cap on the number of post-connect re-discovery passes.</summary>
|
||||
public const int DefaultRediscoverMaxAttempts = 15;
|
||||
|
||||
/// <summary>Default per-pass timeout for <see cref="ITagDiscovery.DiscoverAsync"/> during
|
||||
/// bounded post-connect re-discovery. Bounds the mailbox suspension time; production default 30 s.</summary>
|
||||
public static readonly TimeSpan DefaultRediscoverDiscoverTimeout = TimeSpan.FromSeconds(30);
|
||||
|
||||
public sealed record InitializeRequested(string DriverConfigJson);
|
||||
public sealed record InitializeSucceeded(int Generation);
|
||||
public sealed record InitializeFailed(string Reason, int Generation);
|
||||
@@ -135,6 +139,11 @@ public sealed class DriverInstanceActor : ReceiveActor, IWithTimers
|
||||
/// <summary>Cap on the number of post-connect re-discovery passes — a backstop so a never-stabilising
|
||||
/// (or perpetually-empty) discovered set cannot spin the loop forever. Production default 15.</summary>
|
||||
private readonly int _rediscoverMaxAttempts;
|
||||
|
||||
/// <summary>Per-pass timeout for <see cref="ITagDiscovery.DiscoverAsync"/> during bounded post-connect
|
||||
/// re-discovery. Bounds the mailbox suspension time. Production default 30 s; tests may inject a shorter
|
||||
/// value. Stored to allow injection rather than hardcoding.</summary>
|
||||
private readonly TimeSpan _rediscoverDiscoverTimeout;
|
||||
private readonly ILoggingAdapter _log = Context.GetLogger();
|
||||
private string? _currentConfigJson;
|
||||
|
||||
@@ -192,6 +201,7 @@ public sealed class DriverInstanceActor : ReceiveActor, IWithTimers
|
||||
/// defaults to an empty string when not provided (e.g. in unit tests).</param>
|
||||
/// <param name="rediscoverInterval">Optional interval between post-connect re-discovery passes; defaults to 2 seconds.</param>
|
||||
/// <param name="rediscoverMaxAttempts">Optional cap on re-discovery passes; defaults to 15.</param>
|
||||
/// <param name="rediscoverDiscoverTimeout">Optional per-pass timeout for <see cref="ITagDiscovery.DiscoverAsync"/>; defaults to 30 seconds.</param>
|
||||
public static Props Props(
|
||||
IDriver driver,
|
||||
TimeSpan? reconnectInterval = null,
|
||||
@@ -199,7 +209,8 @@ public sealed class DriverInstanceActor : ReceiveActor, IWithTimers
|
||||
IDriverHealthPublisher? healthPublisher = null,
|
||||
string? clusterId = null,
|
||||
TimeSpan? rediscoverInterval = null,
|
||||
int rediscoverMaxAttempts = DefaultRediscoverMaxAttempts) =>
|
||||
int rediscoverMaxAttempts = DefaultRediscoverMaxAttempts,
|
||||
TimeSpan? rediscoverDiscoverTimeout = null) =>
|
||||
Akka.Actor.Props.Create(() => new DriverInstanceActor(
|
||||
driver,
|
||||
reconnectInterval ?? DefaultReconnectInterval,
|
||||
@@ -207,7 +218,8 @@ public sealed class DriverInstanceActor : ReceiveActor, IWithTimers
|
||||
healthPublisher ?? NullDriverHealthPublisher.Instance,
|
||||
clusterId ?? string.Empty,
|
||||
rediscoverInterval,
|
||||
rediscoverMaxAttempts));
|
||||
rediscoverMaxAttempts,
|
||||
rediscoverDiscoverTimeout));
|
||||
|
||||
/// <summary>
|
||||
/// Returns true when the driver should boot in DEV-STUB mode based on host platform and
|
||||
@@ -241,6 +253,7 @@ public sealed class DriverInstanceActor : ReceiveActor, IWithTimers
|
||||
/// <param name="clusterId">Cluster identifier forwarded in health snapshots.</param>
|
||||
/// <param name="rediscoverInterval">Interval between post-connect re-discovery passes; defaults to 2 seconds.</param>
|
||||
/// <param name="rediscoverMaxAttempts">Cap on the number of re-discovery passes; defaults to 15.</param>
|
||||
/// <param name="rediscoverDiscoverTimeout">Per-pass timeout for <see cref="ITagDiscovery.DiscoverAsync"/>; defaults to 30 seconds.</param>
|
||||
public DriverInstanceActor(
|
||||
IDriver driver,
|
||||
TimeSpan reconnectInterval,
|
||||
@@ -248,7 +261,8 @@ public sealed class DriverInstanceActor : ReceiveActor, IWithTimers
|
||||
IDriverHealthPublisher? healthPublisher = null,
|
||||
string? clusterId = null,
|
||||
TimeSpan? rediscoverInterval = null,
|
||||
int rediscoverMaxAttempts = DefaultRediscoverMaxAttempts)
|
||||
int rediscoverMaxAttempts = DefaultRediscoverMaxAttempts,
|
||||
TimeSpan? rediscoverDiscoverTimeout = null)
|
||||
{
|
||||
_driver = driver;
|
||||
_driverInstanceId = driver.DriverInstanceId;
|
||||
@@ -257,6 +271,7 @@ public sealed class DriverInstanceActor : ReceiveActor, IWithTimers
|
||||
_reconnectInterval = reconnectInterval;
|
||||
_rediscoverInterval = rediscoverInterval ?? DefaultRediscoverInterval;
|
||||
_rediscoverMaxAttempts = rediscoverMaxAttempts;
|
||||
_rediscoverDiscoverTimeout = rediscoverDiscoverTimeout ?? DefaultRediscoverDiscoverTimeout;
|
||||
OtOpcUaTelemetry.DriverInstanceLifecycle.Add(1,
|
||||
new KeyValuePair<string, object?>("event", startStubbed ? "spawn_stub" : "spawn"),
|
||||
new KeyValuePair<string, object?>("driver_type", driver.DriverType));
|
||||
@@ -762,7 +777,7 @@ public sealed class DriverInstanceActor : ReceiveActor, IWithTimers
|
||||
var builder = new CapturingAddressSpaceBuilder();
|
||||
// Bound the browse — ReceiveAsync suspends the mailbox for the whole handler, so an unbounded
|
||||
// DiscoverAsync would block DisconnectObserved / ForceReconnect / writes / health-poll behind it.
|
||||
using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(30));
|
||||
using var cts = new CancellationTokenSource(_rediscoverDiscoverTimeout);
|
||||
// NO ConfigureAwait(false): a genuinely-async DiscoverAsync (Galaxy / OpcUaClient / TwinCAT) must
|
||||
// resume on the actor task scheduler so the Context.Parent.Tell + Timers calls below run with a
|
||||
// live ActorContext. ConfigureAwait(false) would resume off-context and throw
|
||||
|
||||
Reference in New Issue
Block a user