Skip to content

.NET Topology And Host Monitoring Public Interface

.NET per-language interface table of contents · Runtime Monitoring · Host Relocate, Shutdown & Handoff

1. Scope

This document fixes the public interface a .NET application uses to request host shutdown and confirm the operational status of RouteMesh/ ClientServer/Fanout. The status and observation stream only include the values the application needs to judge state and choose a response.

Descriptor revision, lifecycle generation, remote descriptor endpoint, admission/claim/ reservation stage, and Location Store record — used when the framework coordinates topology — aren't included in the public interface. These values can't be changed by the application and are only used by the framework to judge stale state and ownership.

2. Host Lifecycle

Relocating, Relocated, and Draining are provided as separate states because they affect the application differently. In Relocating, new placement and application admission aren't accepted, and current objects are moved to a different node. In Relocated, the move is complete but host infrastructure is kept. In Draining, remaining application processing and resources are cleaned up, without relocation.

public enum ZLinkFrameworkRuntimeState
{
    Preparing = 0,
    Serving = 1,
    Relocating = 2,
    Relocated = 3,
    Draining = 4,
    Stopped = 5,
    Error = 6
}

public enum ZLinkFrameworkRelocationOutcome
{
    Relocated = 0,
    Blocked = 1
}

public enum ZLinkFrameworkRelocationMode
{
    PlannedMaintenance = 0,
    RollingUpdate = 1
}

public enum ZLinkFrameworkRelocationReason
{
    None = 0,
    TargetUnavailable = 1,
    StoreUnavailable = 2,
    RelocationDisabled = 3,
    StateIncompatible = 4,
    DeadlineExceeded = 5,
    RelocationFailed = 6,
    RuntimeNotReady = 7,
    ManualTopologyUnsupported = 8,
    ShutdownRequested = 9,
    OperationInProgress = 10
}

public sealed record ZLinkFrameworkRelocationOptions
{
    public required ZLinkFrameworkRelocationMode Mode { get; init; }
    public long? TargetApplicationVersion { get; init; }
    public TimeSpan? Deadline { get; init; }
}

public readonly record struct ZLinkFrameworkRelocationResult(
    ZLinkFrameworkRelocationMode Mode,
    long TargetApplicationVersion,
    ZLinkFrameworkRelocationOutcome Outcome,
    ZLinkFrameworkRelocationReason Reason);

public enum ZLinkFrameworkTerminationOutcome
{
    Stopped = 0,
    ForceStopped = 1
}

public enum ZLinkFrameworkTerminationReason
{
    None = 0,
    DeadlineExceeded = 1,
    TeardownFailed = 2
}

public readonly record struct ZLinkFrameworkTerminationResult(
    ZLinkFrameworkTerminationOutcome Outcome,
    ZLinkFrameworkTerminationReason Reason);

public readonly record struct ZLinkObservationLoss(
    ulong CoalescedCount,
    ulong DiscardedTerminalCount);

public readonly record struct ZLinkObservedStatus<TStatus>(
    TStatus Status,
    ZLinkObservationLoss Loss)
    where TStatus : notnull;

public readonly record struct ZLinkCoreHwmStatus(
    ulong? ConfiguredMemoryLimitBytes,
    ulong? ConfiguredBudgetBytes,
    ZLinkCoreHwmProfile ConfiguredProfile,
    ulong EffectiveBudgetBytes,
    ulong TotalAppliedHwmBytes,
    ulong CoreQueueAccountedBytes,
    ulong ApplicationAccountedBytes,
    ulong CurrentAccountedBytes,
    ulong ProvisionalAccountedBytes,
    ulong PeakAccountedBytes,
    ulong CompletionCurrentAccountedBytes,
    ulong CompletionPeakAccountedBytes,
    ulong CompletionPendingMessageCount,
    ulong TotalMessagingAccountedBytes,
    ulong MonitorQueueAppliedHwmBytes,
    ulong MonitorQueueAccountedBytes,
    ulong TotalInstanceAppliedHwmBytes,
    ulong TotalInstanceAccountedBytes,
    ulong BlockedRatioPpm,
    ulong ActiveDirectionalQueueCount,
    ulong ActiveCompletionDirectionalQueueCount,
    ulong ActiveSendQueueCount,
    ulong ActiveReceiveQueueCount,
    ulong OutstandingApplicationLeaseCount,
    ulong RetiredQueueCount,
    ulong DeferredOriginCreditBytes);

public readonly record struct ZLinkApplicationJobQueueStatus(
    ZLinkApplicationJobQueueProfile ConfiguredProfile,
    ulong? ConfiguredManualMax,
    uint ConfiguredPauseThresholdPercent,
    uint ConfiguredResumeThresholdPercent,
    ulong EffectiveProcessorCount,
    ulong EffectiveMaxQueuedApplicationJobs,
    ulong PausePermitCount,
    ulong ResumePermitCount,
    ulong ReservedSupplyPermits,
    ulong QueuedApplicationJobs,
    ulong PermitsInUse,
    ulong PeakPermitsInUse,
    ulong CapacityWaiters,
    ulong CapacityWaitCount,
    TimeSpan CapacityWaitDuration,
    ZLinkApplicationJobQueuePressureState PressureState,
    TimeSpan CurrentPauseDuration);

public readonly record struct ZLinkHostCapacityStatus(
    ulong MeasurementEpoch,
    ZLinkCoreHwmStatus CoreHwm,
    ZLinkApplicationJobQueueStatus ApplicationJobQueue);

public sealed record ZLinkFrameworkRuntimeStatus(
    ZLinkFrameworkRuntimeState State,
    bool IsReady,
    bool AcceptingWork,
    DateTimeOffset? Deadline,
    ZLinkFrameworkRelocationResult? RelocationResult,
    ZLinkFrameworkTerminationResult? TerminationResult,
    ulong Sequence,
    DateTimeOffset ObservedAt,
    ZLinkHostCapacityStatus Capacity = default,
    bool SafeToShutdown = true);

public enum ZLinkListenerKind
{
    RouteMesh,
    ClientServer,
    Fanout,
    Stream,
}

public sealed record ZLinkListenerStatus(
    ZLinkListenerKind Kind,
    string Name,
    string Endpoint,
    DateTimeOffset ObservedAt);

public interface IZLinkFrameworkRuntime
{
    ZLinkFrameworkRuntimeStatus Status { get; }
    void ResetCapacityMetrics();
    ZLinkListenerStatus GetListenerStatus(ZLinkListenerKind kind, string name);

    IAsyncEnumerable<ZLinkObservedStatus<ZLinkFrameworkRuntimeStatus>> ObserveAsync(
        CancellationToken cancellationToken = default);

    ValueTask<ZLinkFrameworkRelocationResult> RelocateAsync(
        ZLinkFrameworkRelocationOptions options,
        CancellationToken cancellationToken = default);

    ValueTask<ZLinkFrameworkTerminationResult> ShutdownAsync(
        TimeSpan? deadline = null,
        CancellationToken cancellationToken = default);
}

In ZLinkCoreHwmStatus, ApplicationAccountedBytes, OutstandingApplicationLeaseCount, RetiredQueueCount, and DeferredOriginCreditBytes are ABI-reserved compatibility fields and are always 0 since 0.13.1. The framework projects them unchanged and does not reinterpret them as Application Job Queue pressure.

GetListenerStatus(kind, name) is the listener state query of Network listener identity §3.1. name is the configured MeshName, ChannelName, or StreamNodeName. A configuration error defined in §3.1 is thrown as a ZLinkFrameworkException whose Kind is NotConfigured.

AcceptingWork has type bool. Observation of readiness and new-work acceptance state follows Runtime monitoring §11.

Host relocation and shutdown defines target selection, deadline, lifecycle outcomes, and waiter handling for RelocateAsync(...) and ShutdownAsync(...). .NET maps an invalid mode/version combination to ArgumentException.

3. Common Topology State

Host state represents the whole process's lifecycle. ZLinkTopologyState represents the availability of one topology registered by MeshName or ChannelName. Even if the host is Serving, only that specific topology can be Degraded if it has no ready peer or target.

Topology status only provides closed states from which the user can judge readiness and failure scope. ZLinkTopologyReason is used by the application to decide whether to check configuration or observe again later. Detailed transport or Store errors are recorded in .NET logging and tracing.

public enum ZLinkTopologyState
{
    Starting = 0,
    Ready = 1,
    Degraded = 2,
    Stopping = 3,
    Stopped = 4,
    Failed = 5
}

public enum ZLinkTopologyReason
{
    RuntimeNotReady = 0,
    NoReadyPeer = 1,
    NoReadyTarget = 2,
    LocationUnavailable = 3,
    CapacityExceeded = 4,
    Draining = 5,
    InternalFailure = 6
}

public enum ZLinkPeerState
{
    Connecting = 0,
    Ready = 1,
    Draining = 2,
    NotConnected = 3,
    NotRequired = 4
}

public sealed record ZLinkChannelStatus(
    string ChannelName,
    bool IsReady,
    int ReadyTargetCount);

public sealed record ZLinkPeerStatus(
    RoutingId NodeRid,
    ZLinkPeerState State,
    ZLinkTopologyReason? UnavailableReason);

NodeRid is the MeshNode's transport identity, used to correlate a peer with log and deployment information. A separate operational node identity isn't added. Endpoint and connection generation aren't provided in public status.

4. RouteMesh

RouteMesh status shows, at once, peer connections of the same MeshName, channel readiness, and object placement availability. Placement count only aggregates active objects that exist in this process.

public sealed record ZLinkPlacementStatus(
    bool IsAvailable,
    int ActiveActorCount,
    int ActiveSpotCount,
    ZLinkTopologyReason? UnavailableReason);

public sealed record ZLinkRouteMeshStatus(
    string MeshName,
    ZLinkTopologyState State,
    bool IsReady,
    int ReadyPeerCount,
    IReadOnlyList<ZLinkChannelStatus> Channels,
    IReadOnlyList<ZLinkPeerStatus> Peers,
    ZLinkPlacementStatus Placement,
    ulong Sequence,
    DateTimeOffset ObservedAt);

public interface IZLinkRouteMeshRuntime
{
    ZLinkRouteMeshStatus GetStatus(string meshName);

    IAsyncEnumerable<ZLinkObservedStatus<ZLinkRouteMeshStatus>> ObserveAsync(
        string meshName,
        CancellationToken cancellationToken = default);
}

IsReady is true when the host is Serving and that RouteMesh can process application traffic. ReadyPeerCount is the number of remote MeshNodes in ready state. Since a local channel can also be used normally, having 0 peers alone doesn't make every RouteMesh judged unavailable.

Channel topology §8 defines NotRequired and NotConnected peer status and liveness accounting.

Runtime monitoring defines the observed meaning of Placement.IsAvailable.

5. ClientServer

ClientServer channel §4 defines the local and remote target set and selection conditions.

public enum ZLinkClientServerRole
{
    Client = 1,
    Server = 2,
    ClientAndServer = 3
}

public sealed record ZLinkClientServerTargetStatus(
    RoutingId NodeRid,
    int Weight,
    ZLinkPeerState State,
    ZLinkTopologyReason? UnavailableReason);

public sealed record ZLinkClientServerStatus(
    string ChannelName,
    ZLinkClientServerRole LocalRole,
    ZLinkTopologyState State,
    bool IsReady,
    int ReadyTargetCount,
    IReadOnlyList<ZLinkClientServerTargetStatus> Targets,
    ulong Sequence,
    DateTimeOffset ObservedAt);

public interface IZLinkClientServerRuntime
{
    ZLinkClientServerStatus GetStatus(string channelName);

    IAsyncEnumerable<ZLinkObservedStatus<ZLinkClientServerStatus>> ObserveAsync(
        string channelName,
        CancellationToken cancellationToken = default);
}

ReadyTargetCount and Targets project the target status defined by ClientServer channel §4.

6. Fanout

Fanout runtime status shows the publisher connections currently available to an automatic subscriber. An individual publisher's endpoint, discovery source, and generation are managed by the framework.

public sealed record ZLinkFanoutStatus(
    string ChannelName,
    ZLinkTopologyState State,
    bool IsReady,
    int ReadyPublisherCount,
    IReadOnlyList<ZLinkPeerStatus> Publishers,
    ulong Sequence,
    DateTimeOffset ObservedAt);

public interface IZLinkFanoutRuntime
{
    ZLinkFanoutStatus GetStatus(string channelName);

    IAsyncEnumerable<ZLinkObservedStatus<ZLinkFanoutStatus>> ObserveAsync(
        string channelName,
        CancellationToken cancellationToken = default);
}

The connection list of a manual subscriber is owned by the manual connection API. Querying a manual ChannelName through IZLinkFanoutRuntime raises ZLinkConfigurationException.

7. Observation Stream

ObserveAsync(...) delivers ZLinkObservedStatus<TStatus>; Loss is ZLinkObservationLoss, and CoalescedCount and DiscardedTerminalCount are ulong. Runtime monitoring defines coalescing, loss, sequence, and SafeToShutdown. CancellationToken is the .NET enumeration cancellation argument.

8. Dispatch Policy And Diagnostics

The unhandled-message policy and diagnostics configuration are handled by separate child interfaces under ConfigureDispatch(). Core HWM and application-job-queue settings are owned by the independent ConfigureInboundDispatch() surface. Tracing mode is owned by the diagnostics child; observer, error sink, and file output aren't provided.

public enum ZLinkUnhandledDispatchAction
{
    ReplyError = 0,
    LogAndDrop = 1,
    Drop = 2,
    Throw = 3
}

public interface IZLinkUnhandledDispatchOptions
{
    ZLinkUnhandledDispatchAction Request { get; set; }
    ZLinkUnhandledDispatchAction Send { get; set; }
    ZLinkUnhandledDispatchAction Publish { get; set; }
}

public enum ZLinkDiagnosticsLevel
{
    Off = 0,
    Errors = 1,
    Normal = 2,
    Detailed = 3
}

public interface IZLinkDiagnosticsOptions
{
    IZLinkDiagnosticsOptions SetLevel(ZLinkDiagnosticsLevel level);
    IZLinkDiagnosticsOptions SetSampleRate(double rate);
    IZLinkDiagnosticsOptions IncludeMessageSizes(bool include);
}

public interface IZLinkDispatchOptions
{
    IZLinkUnhandledDispatchOptions Unhandled { get; }
    IZLinkDiagnosticsOptions Diagnostics { get; }
}

public interface IZLinkInboundDispatchOptions
{
    ulong? CoreHwmMemoryLimitBytes { get; set; }
    ulong? CoreHwmBudgetBytes { get; set; }
    ZLinkCoreHwmProfile CoreHwmProfile { get; set; }
    ZLinkApplicationJobQueueProfile ApplicationJobQueueProfile { get; set; }
    ulong? MaxQueuedApplicationJobs { get; set; }
    uint ApplicationJobQueuePauseThresholdPercent { get; set; }
    uint ApplicationJobQueueResumeThresholdPercent { get; set; }
}

public interface IZLinkDiagnosticsRuntime
{
    ZLinkDiagnosticsLevel Level { get; set; }
    Task SetLevelAsync(ZLinkDiagnosticsLevel level);
}

SetSampleRate(...) only allows 0.0 to 1.0 inclusive. Out of range raises ArgumentOutOfRangeException. Recording message size adds the payload size distribution to telemetry, without recording payload content.

IZLinkDiagnosticsRuntime is a process singleton obtained from DI. SetLevelAsync is the canonical asynchronous control; the Level setter is the synchronous bridge over it. Use SetLevelAsync from framework execution contexts such as handlers and callbacks. Reading Level returns the level currently applied to the process. Changing the value applies the new level starting from message processing that begins afterward. The change is an atomic state change that doesn't wait for message processing. A record already in the telemetry queue can be delivered or dropped, and turning it back on doesn't retroactively create records for earlier processing.

The .NET runtime provides trace as ActivitySource, metric as System.Diagnostics.Metrics.Meter, and log as Microsoft.Extensions.Logging.ILogger. The export destination and log storage location are decided by the application's telemetry and logging configuration. The framework doesn't take a file path or provide its own exporter lifetime as a public API.