namespace ZB.MOM.WW.OtOpcUa.Core.Abstractions;
///
/// Abstraction over the Phase 6.1 resilience pipeline that wraps a single driver instance's
/// capability calls (retry / circuit-breaker / in-flight accounting / tracker telemetry). The Runtime
/// dispatch layer (DriverInstanceActor) consumes this interface instead of the concrete
/// CapabilityInvoker so the actor assembly does NOT pull in
/// ZB.MOM.WW.OtOpcUa.Core (which drags in Polly + driver hosting) — the same boundary
/// rationale as . The fused Host binds a real invoker (built by
/// ) per spawned driver; when none is supplied the
/// dispatch layer uses , a genuine pass-through.
///
///
/// The method shapes mirror CapabilityInvoker exactly so the concrete invoker satisfies
/// this interface without adapters. Callers pass the resolved hostName per call (a
/// multi-host driver resolves it from the tag reference via ;
/// a single-host driver passes its ) so per-host breaker
/// isolation + in-flight-depth accounting key on the right target.
///
public interface IDriverCapabilityInvoker
{
/// Execute a value-returning capability call through the per-capability pipeline.
/// Return type of the underlying driver call.
/// The driver capability being executed.
/// The resolved host name for pipeline keying + status tracking.
/// The async function to execute (the raw driver-capability call).
/// Cancellation token for the operation.
/// The result of the underlying driver call.
ValueTask ExecuteAsync(
DriverCapability capability,
string hostName,
Func> callSite,
CancellationToken cancellationToken);
/// Execute a void-returning capability call through the per-capability pipeline.
/// The driver capability being executed.
/// The resolved host name for pipeline keying + status tracking.
/// The async function to execute (the raw driver-capability call).
/// Cancellation token for the operation.
/// A task that represents the asynchronous operation.
ValueTask ExecuteAsync(
DriverCapability capability,
string hostName,
Func callSite,
CancellationToken cancellationToken);
///
/// Execute a call honoring idempotence semantics — when
/// is false, retries are disabled regardless of the
/// configured policy; when true, the call runs through the Write pipeline which may
/// retry if the tier configuration permits. The current production default is false
/// (R2-02/S-8): DriverInstanceActor.HandleWriteAsync passes isIdempotent: false so a
/// command-shaped write is never replayed; per-tag opt-in via
/// is the unshipped forward path.
///
/// Return type of the underlying driver write call.
/// The resolved host name for pipeline keying + status tracking.
/// Whether the write operation is safe to retry.
/// The async function to execute (the raw driver write call).
/// Cancellation token for the operation.
/// The result of the underlying driver write call.
ValueTask ExecuteWriteAsync(
string hostName,
bool isIdempotent,
Func> callSite,
CancellationToken cancellationToken);
}
///
/// Pass-through that invokes the call site directly with
/// NO pipeline — no timeout, retry, breaker, or telemetry. Bound when the dispatch layer is
/// constructed without a real invoker (unit tests, the F7 skeleton path, admin-only nodes that
/// never run drivers). Keeps behavior byte-for-byte identical to a raw driver call so existing
/// dispatch-layer tests are unaffected by the resilience wiring.
///
public sealed class NullDriverCapabilityInvoker : IDriverCapabilityInvoker
{
/// The shared singleton instance.
public static readonly NullDriverCapabilityInvoker Instance = new();
private NullDriverCapabilityInvoker() { }
///
public ValueTask ExecuteAsync(
DriverCapability capability,
string hostName,
Func> callSite,
CancellationToken cancellationToken) => callSite(cancellationToken);
///
public ValueTask ExecuteAsync(
DriverCapability capability,
string hostName,
Func callSite,
CancellationToken cancellationToken) => callSite(cancellationToken);
///
public ValueTask ExecuteWriteAsync(
string hostName,
bool isIdempotent,
Func> callSite,
CancellationToken cancellationToken) => callSite(cancellationToken);
}