fix(galaxy): #875 Galaxy initialize gets a 20 s budget via per-driver-type capability defaults

Gate F (#761) against the VD03 gateway: Galaxy initialize (session open +
platform seed) took 4–5 s against Tier A's 5 s Initialize timeout, so 10 of 40
restarts failed, paid a 10 s retry and left a killed gateway worker.

DriverFactoryRegistry.Register takes optional capabilityDefaults per driver
type (GetCapabilityDefaults); DriverResilienceOptionsParser layers them over the
tier table and under the per-instance ResilienceConfig; the Host wires the
registry into DriverCapabilityInvokerFactory. Galaxy registers Initialize =
20 s (no retry, breaker 2), under the actor's 30 s pessimistic bound.

Claude-Session: https://claude.ai/code/session_01GT67AD99zQQqpLCVm3p7xk
This commit is contained in:
Joseph Doherty
2026-11-11 18:44:44 -05:00
parent 2be43aa984
commit 95bde828eb
8 changed files with 157 additions and 7 deletions
@@ -1,3 +1,4 @@
using ZB.MOM.WW.OtOpcUa.Core.Resilience;
using System.Text.Json;
using System.Text.Json.Serialization;
using Microsoft.Extensions.Logging;
@@ -45,9 +46,23 @@ public static class GalaxyDriverFactoryExtensions
ArgumentNullException.ThrowIfNull(registry);
ArgumentNullException.ThrowIfNull(secretResolver);
registry.Register(DriverTypeName,
(id, json) => CreateInstance(id, json, loggerFactory, secretResolver, ackIdentityDirectory));
(id, json) => CreateInstance(id, json, loggerFactory, secretResolver, ackIdentityDirectory),
capabilityDefaults: CapabilityDefaults);
}
/// <summary>
/// #875: Galaxy initialize (gateway session open + the per-template platform seed) took 4–5 s against the
/// real VD03 gateway — right at the Tier A 5 s Initialize timeout, so a quarter of restarts failed and paid a
/// 10 s retry plus a killed gateway worker. 20 s gives it 4× headroom and stays under the actor's 30 s
/// pessimistic bound (<c>DriverInstanceActor.DefaultInitializeTimeout</c>). No retry and breaker threshold 2,
/// as in every tier's Initialize policy. A per-instance ResilienceConfig still overrides it.
/// </summary>
internal static readonly IReadOnlyDictionary<DriverCapability, CapabilityPolicy> CapabilityDefaults =
new Dictionary<DriverCapability, CapabilityPolicy>
{
[DriverCapability.Initialize] = new(TimeoutSeconds: 20, RetryCount: 0, BreakerFailureThreshold: 2),
};
/// <summary>
/// Convenience for tests + standalone callers. Uses the <see cref="NullSecretResolver"/>
/// null-object, so the <c>secret:</c> API-key arm resolves fail-closed (absent) — callers