Runtime Status Query and Operational Diagnostics¶
Observability topic table of contents · Spec table of contents · Next: 02. Runtime Metrics
Defines the public contract for the complete host/topology status at a specific point in time, the status-change stream, and structured-log identifiers. The ownership boundary with other documents in this topic follows the Observability responsibility map.
1. Runtime Status Query Overview¶
An application operator queries the framework runtime's current status once, observes subsequent changes, and uses logs to determine why a status changed. The application uses this information to judge whether the runtime can accept new work, the scope of a failure, and relocation/shutdown results.
This document owns the complete status at a specific point in time, the status-change stream, and structured-log identifiers. The name/unit/label of numbers accumulated or collected over time is owned by Runtime Metrics; the progress record of one message is owned by Message Flow Tracing; the state transitions of relocation and shutdown are owned by Host Relocation And Shutdown. See the topic README for the complete ownership map.
2. Roles and Responsibilities · Values Not Exposed Publicly¶
| Party | Responsibility |
|---|---|
| Application | Queries and observes status by registered name, and configures the logger provider and backend. |
| Framework | Combines internal service values into a complete status and records standard identifiers for state changes. |
| Provider | Delivers logs to the logger backend the application chose. Ensures a provider failure doesn't change the runtime result. |
| Remote runtime | Publishes its own service availability and operational state. The current runtime reflects this in topology status. |
The descriptor revision, indicating the order of changes to remote registration information, and the owner lease, indicating whether a host can keep using its current lifecycle's ownership, are used only for internal judgment. The public interface doesn't expose these two values, the internal state of work acceptance, claims, capacity reservation, socket state, exporters, storage, raw event DTOs, or native handles.
3. Host State — Values Read at Once¶
The application reads per-feature status by the name it registered at startup. It doesn't directly combine values from several internal services.
The registration names introduced here are as follows.
- The runtime unit that provides RouteMesh peer connections and Channel messaging within one process is called a MeshNode. The logical runtime where multiple MeshNodes share the same messaging rules is called a RouteMesh, and the startup registration name identifying one RouteMesh is called a MeshName.
- The startup registration name identifying one Channel is called a ChannelName.
- The topology where Client and Server exchange requests and replies under a ChannelName is called a ClientServer Channel.
- The logical execution unit with an address and state that receives messages is called a Spot.
- The state in which every per-feature serving condition is met, allowing application messages to be received, is called Ready.
| State scope | Values checked in one status |
|---|---|
| Host | Runtime state, ready status, new-work acceptance, deadline, relocation/shutdown result, and inbound dispatch state |
| RouteMesh | MeshName, overall state, ready peer count, per-Channel ready target count, per-peer operational state, and the current process's Actor/Spot count |
| ClientServer | ChannelName, local role, overall state, ready target count, and per-target operational state/weight |
| Automatic fanout | ChannelName, overall state, number of publishers being connected to, and ready publisher count |
Status is an immutable value that can be kept after the call ends. It doesn't reference a native handle, caller buffer, payload, or application metadata, so the caller holding onto the status doesn't pin runtime-internal resources.
The following C# is a non-normative excerpt showing the common behavior. It doesn't require the same signature in other languages. The precise type and signature are set by .NET Topology Monitoring.
public interface IZLinkRouteMeshRuntime
{
ZLinkRouteMeshStatus GetStatus(string meshName); // reads the current state of the registered RouteMesh.
IAsyncEnumerable<ZLinkObservedStatus<ZLinkRouteMeshStatus>> ObserveAsync(
string meshName,
CancellationToken cancellationToken = default); // receives subsequent complete states and the loss total, in order.
}
Host state doesn't belong to a specific MeshName. The final results of
relocation and shutdown are also provided just once, in host status.
Host runtime state is closed to the following values. A value not in this table must not be added. The procedure of blocking new work and cleaning up already-accepted work within a time limit is called drain. That time limit is called a deadline.
| Value | Meaning the application observes |
|---|---|
preparing |
Validating startup configuration and preparing the runtime. |
serving |
Can accept new application operations. |
relocating |
Stopped accepting new work and is moving stateful objects to another node. |
relocated |
Relocation finished; infrastructure and connections are kept. |
draining |
Cleaning up remaining processing and resources without relocation. |
stopped |
Runtime and infrastructure cleanup are finished. |
error |
An error occurred that prevents continuing to operate the runtime. |
IsReady is true only when State is serving. AcceptingWork is a
separate value indicating whether the current host accepts new application
operations, and the two values aren't reinterpreted as conditions that
substitute for each other. The precise meaning of relocation option,
deadline, and result is set by
Host Relocation And Shutdown.
Host status also provides the
SafeToShutdown observation value,
indicating when the source runtime can be shut down safely after
relocation.
- For a relocation operation it started, the source runtime publishes
SafeToShutdownto its own host status only after every relocation unit has reached the point where its Message Follow route — the routing that keeps delivering messages arriving at the previous owner to the new owner after relocation — can be removed (based on follow-duration expiry), and each unit's cutover retransmission window has ended. Both conditions are events occurring on the source, so this judgment uses no other node's clock. - This value isn't a completion ACK sent by the target or any other party — the source publishes it. A deployment orchestrator confirms it through the status query and change observation in §6.
- Calling
Shutdown— which puts the runtime into termination and stops it from admitting new operations — before it is published is still allowed. In that case the remaining Message Follow routes disappear with the transport, and a request from a sender still caching the previous route can end withUnavailable.
The definitions of Message Follow and the cutover retransmission window are owned by Complete Actor And Spot Relocation Flow.
4. The Capacity Fields of Host Status¶
The capacity fields in host status coherently read the Core HWM snapshot and the Application job queue snapshot — the shared supply-permit queue a host holds before an application callback starts — from one measurement epoch. It doesn't walk queues to build a snapshot.
The Core HWM snapshot lets you observe: configured memory limit, manual
budget, and profile; effective budget; total applied HWM; the core
queue's current, provisional, and peak accounted bytes; completion
current, peak, and pending; total messaging, monitor-queue
applied/accounted, and total-instance applied/accounted bytes; blocked
ratio; and active ordinary/completion/send/receive queue counts. The four
fields application accounted bytes, outstanding application lease,
retired queue, and deferred origin credit are reserved fields kept for
ABI compatibility and have always been 0 since version 0.13.1. This
doesn't mean an
application byte HWM or lease exists. The framework projects the Core
runtime snapshot unchanged and neither recomputes it nor assigns it a
different meaning.
Under this Core meaning, DEALER-ROUTER reply bytes are included in
core_queue_accounted_bytes, current, provisional, peak, and total messaging,
and are excluded from Completion current, peak, pending, and direction count.
Only reply bytes on a ROUTER-ROUTER Completion connection are included in the
Completion fields. Framework status uses the topology-specific classification,
field names, snapshot layout, and ABI version from the Core runtime snapshot.
The application job queue snapshot lets you observe: configured
profile/manual max; configured pause/resume percent; effective processor
count/effective max; computed pause/resume permit count; reserved supply
permits; queued application jobs; permits in use/peak; the running|paused
pressure state; current pause duration; and capacity waiter/wait
count/duration. Reset keeps configuration, the pressure state, and current
pause duration, and advances the measurement epoch, while pressure
transition count, cumulative pause duration, and flow-state config failure
count are set to 0. A concurrent event is included in exactly one epoch —
the previous or the new epoch — and peak can't be smaller than current. The
ownership of the measurement epoch and the instrument that continuously
tracks this snapshot's values is defined by
Runtime Metrics §3;
this document only covers what can be queried at one point in time.
This status doesn't include payload, Actor ID, Spot ID — a Spot's global logical address — session ID, RID, endpoint, message type, or a per-owner list. A per-owner top-N isn't part of the public contract.
5. Topology State — RouteMesh, ClientServer, Automatic Fanout¶
Topology state has a different scope from host state. Host state is
the process-wide startup, relocation, and shutdown progress. Topology
state indicates whether one RouteMesh/ClientServer/automatic fanout
registered under a MeshName or ChannelName can currently process
application messages.
So even if the host is serving, if a specific ClientServer Channel has no
ready target, only that topology can be degraded. Conversely, if the
host is relocating, relocated, or draining, every topology's
IsReady is false even if connections remain. At this point, the
connected peer/target counts still reflect the actual current connection
state — the counts aren't changed to 0 just because the host isn't
accepting application traffic.
| State kind | Allowed values |
|---|---|
| Topology state | starting, ready, degraded, stopping, stopped, failed |
| Topology reason | runtime_not_ready, no_ready_peer, no_ready_target, location_unavailable, capacity_exceeded, draining, internal_failure |
| Peer state | connecting, ready, draining, not_connected, not_required |
| ClientServer local role | client, server, client_and_server |
| Topology state | Meaning |
|---|---|
starting |
Preparing that topology's listener, connections, and registration. |
ready |
The host is serving and that topology can process application messages. |
degraded |
Some peers/targets or the Location Store are unavailable, so that topology can't fully provide its functionality. |
stopping |
Cleaning up that topology's already-accepted work and connections due to host shutdown. |
stopped |
That topology's work and connection cleanup is finished. |
failed |
An error occurred that prevents continuing to operate that topology. |
A RouteMesh peer provides a node's transport identity, Routing ID, as the Node RID value. Endpoint, descriptor revision, and connection generation aren't provided.
Peer state distinguishes two cases where there's no connection.
| Peer state | Meaning | Ready/failure aggregation |
|---|---|---|
not_connected |
The topology requires a connection but there's currently no ready connection. | Excluded from ready peer count. Reflected in topology degraded status and liveness/health failure aggregation. |
not_required |
Both MeshNodes are Object Client and neither has RouteMesh Channel Server membership, so no connection is needed. Automatic excludes it at the descriptor-check stage; Manual confirms it at handshake. | Excluded from ready peer count. Also not a target for liveness probe/reconnect/health failure aggregation. |
A not_required peer is still left in the status's peer list. This lets an
operator distinguish a normal connection omission from a connection
failure. This state alone doesn't cause a RouteMesh to become degraded.
RouteMesh placement state provides whether new objects are accepted and the current active Actor/Spot count. Status separately provides the count of Spots and the Actors processing application messages within them. The per-type capacity reservation registered at startup, the activation barrier blocking first-message delivery before Spot initialization finishes, and internal capacity counters, aren't provided.
Placement's IsAvailable is true only when the host is serving and is
an Object Server, placement weight is positive, and there's headroom in
both Actor/Spot capacity and activation concurrency. Activation
concurrency's current value and limit aren't exposed as a separate field
in public status.
The weight used for the new-target selection
ratio is a signed integer 0..10000. A value of 0 excludes it from being
chosen as a new placement target.
A ClientServer Server in the same process is also a candidate on equal
footing with a remote Server. Status provides target count and each
target's state/weight. client_and_server means both roles are registered
under the same ChannelName — it isn't a separate registration role.
The ready judgment of an automatic fanout publisher is owned by
transport liveness §4,
and monitoring status shows its result. That ready starts per publisher with
the first application record or
liveness beacon received
and ends with a disconnect or 15 seconds without a record is that document's
rule. A connection plan or connect acceptance alone doesn't make it ready.
6. Observing State Changes — Sequence and the Complete Status¶
Each language provides a current-status query and an async change observation. Names and types are set by each language's interface.
var current = routeMeshRuntime.GetStatus("game-mesh");
// readiness and target state are contained in one value built at the same point in time.
await foreach (var observed in routeMeshRuntime.ObserveAsync("game-mesh", cancellationToken))
{
await RecordStatusAsync(observed.Status, cancellationToken);
// observed.Loss is the count this observer has missed so far.
// observation code doesn't change routing or lifecycle decisions.
}
Status includes a Sequence that monotonically increases within the
runtime instance, and an observation time. Within the same source, a
larger Sequence is a later state. Values from different sources aren't
compared. Sequence can restart from 0 when the process restarts.
Each item in the change stream is a complete status, not an event
carrying only some fields. A general-purpose event DTO combining
nullable fields isn't provided. If an observer notices a Sequence gap, it
re-queries the current status to restore every field.
7. When the Observer Is Slow — Source, Coalescing, and the Lost-Update Count¶
7.1 Definition of a Source¶
The unit of coalescing, a source, equals the thing that owns a
Sequence. Since each status item carries one Sequence, the entity
issuing that Sequence is the source.
| Stream kind | Source | Source key |
|---|---|---|
| Host status | This one runtime instance | The runtime instance ID. One for the process's lifetime |
| Topology status | One topology runtime | RouteMesh uses MeshName; ClientServer/fanout use ChannelName |
Peers and object moves aren't separate sources. They're carried as a
list inside topology status and don't have their own Sequence. If one
peer changes, that topology's whole status is published with a new
Sequence. To have a separate slot per peer or per move, a separate
stream and per-language contract must be defined first — until then it
isn't a unit of this coalescing rule.
A source key is created when that target first becomes observable, and
removed after its terminal status is delivered or discarded. While the
key is alive, Sequence increases monotonically within that key.
7.2 Coalescing¶
The framework can coalesce intermediate status so a slow observer doesn't delay message dispatch, location claims, or host lifecycle. Coalescing is a method that keeps one latest-status slot per source. A previous intermediate status of the same source is replaced by the latest status. Even so, the following results are guaranteed.
- Delivers the most recent status's
Sequencefor kept sources. - Terminal statuses for relocation and shutdown aren't overwritten by an intermediate status.
- One observer's delay, cancellation, or failure doesn't affect other observers or the runtime result.
- A cumulative field reflects the latest value even after coalescing. Increments to backpressure and drop counters aren't lost to coalescing.
Even with the one-slot-per-source structure, if an observer continues without reading, terminated sources' terminal statuses accumulate. The retained amount is capped, and once the cap is exceeded, the framework discards the oldest terminal status first. A structure that retains terminal status indefinitely isn't allowed, since one slow observer would exhaust runtime memory.
An observer must be able to learn about the loss when something is discarded. Since loss count differs per observer, it's not put inside the status — status is a value shared among observers, and putting a per-observer value in it would make it unshareable.
Instead, the unit the stream delivers is defined as a pair of status and delivery information.
| Component | Content |
|---|---|
| status | The complete status, same as before. Shared among observers |
| lost-update count | The number of items this observer has lost since starting its subscription |
The lost-update count counts what disappeared via intermediate-status
coalescing and what disappeared via terminal discard, separately.
Merging the two would make it impossible for an observer to distinguish
"skipped while catching up" from "never seen at all." Both counters start at
0 per subscription, increase monotonically and independently, and saturate at
9223372036854775807 (2^63 - 1). A language's integer representation does not
change this observable range.
A whole-runtime metric can't substitute for this value — it can't
determine which observer lost what. An observer learns about loss from
this value's increase and a Sequence gap.
A source's latest slot is removed once that source's lifecycle ends and its terminal status is delivered or discarded. A removed source drops out of the "kept sources" above.
The framework doesn't end a stream just because an observer's queue is full. It relies only on the coalescing and retention cap above to let the observer catch up — the stream stays open even if an observer stays slow. Canceling observation only ends that stream. It doesn't cancel already-accepted runtime work or other observers.
8. Querying an Object's Current Location¶
An operational tool can precisely query the current location by Actor ID or Spot ID, or enumerate the management scope of stored location information by page. This result isn't used as a messaging target or placement selector.
The fields, page size, and cache contract provided by the Location Store, the reference storage for location information, are set by Location Runtime's Operational Query.
Per-ID lookup and paging return Creating, Ready, and Unavailable
entries with the same meaning. A missing record produces an empty per-ID
result and is absent from a page. A Store query failure is an Unavailable
framework error and never returns part of a page as a successful result.
9. Structured Log¶
The framework records why a state changed to a standard structured logger. The application configures the logger provider and backend. The framework public interface doesn't provide a sink, file path, exporter lifecycle, or event DTO.
The following identifiers use the same string in every language.
Among them, zlink.runtime.host.relocation_changed also records changes to
Relocation mode — the
caller intent that decides which application version the host's stateful
objects move to.
| Identifier | Change it records |
|---|---|
zlink.runtime.mesh_node.state_changed |
A MeshNode's lifecycle or ready state changed. |
zlink.runtime.mesh_node.peer_changed |
A peer's work acceptance, ready, or service state changed. |
zlink.runtime.mesh_node.channel_changed |
A Channel's weight, ready target count, or selectability changed. |
zlink.runtime.object.placement_changed |
Placement aggregation changed due to reservation, Ready, abort, capacity exhaustion, or relocation. |
zlink.runtime.mesh_node.routing_id_conflict |
An automatic Node RID owner claim failed due to an active conflict. |
zlink.runtime.host.relocation_changed |
Relocation mode, effective target version, host state, or terminal result changed. |
zlink.runtime.host.termination_changed |
Shutdown state or terminal result changed. |
zlink.runtime.relocation.changed |
An Actor or Spot relocation phase/recovery state changed, or one unit's admission interruption time exceeded 1 second. |
zlink.runtime.client_server.state_changed |
ClientServer local role, lifecycle, or ready state changed. |
zlink.runtime.client_server.server_changed |
A ClientServer target's weight, ready, or service state changed. |
zlink.runtime.fanout.publisher_changed |
An automatic publisher's connection target or ready state changed. |
zlink.runtime.location.store_changed |
The Location Store changed between ready and degraded. |
A log records timestamp, source kind, and registration name. For relevant changes, it also records Node RID, weight, reason, and state. Payload, metadata, Actor ID, Spot ID, owner token, generation, raw frame, and native handle aren't recorded.
A structured log or dedicated metric isn't recorded when work enters or leaves a mailbox. The framework doesn't turn a mailbox's individual enqueue/dequeue and turn into operational events. Operation failure is aggregated into drop/timeout/backpressure metrics, and individual message delay is investigated via Message Flow Tracing.
Publisher state is recorded as one of excluded_draining, excluded_stale,
reconnecting, or disconnected. A log is a judgment at the time it was
recorded and isn't the basis for current location or state. Current state
is read from fanout status.
If a relocation unit's time from source admission seal to the terminal
success or failure of the one-way cutover submit exceeds 1 second,
zlink.runtime.relocation.changed records unit_kind and, where needed,
execution_mode, as well as interruption_target_exceeded=true and the actual
duration. unit_kind is one of actor, instance_spot, user_spot.
This is an operational warning and doesn't change the relocation outcome
or recovery judgment. Actor ID and Spot ID aren't put in structured logs
and are only checked via limited-scope trace. The opening of target admission
isn't acknowledged to the source and is observed through target-local
status and tracing.
10. Startup and Failure¶
- Requesting status for an unregistered
MeshNameorChannelNameis a configuration error. - Requesting automatic status for a fanout
ChannelNameregistered only with a manual subscriber is a configuration error. - A runtime with no Location Store shows store state as
not_configured. - If object role is
ClientorServerbut there's no Location Store, host startup fails. - Runtime status stays usable even if metrics or trace are turned off.
- A logger provider failure doesn't change message dispatch, reply, topology coordination, or host lifecycle results.
11. Verification Requirements¶
The following is verified using only the public surface — the
host/topology status query API, the status-change observation API, the
SafeToShutdown observation value, the operational tool's location query
API, and structured-log identifiers. Each item leads to one implementation
or contract test.
Host status
- Readiness, whether new work is accepted, and relocation and shutdown results can be judged from host status alone.
- Public status has no endpoint, descriptor revision, owner lease, claim, reservation, native handle, or raw event DTO.
SafeToShutdownisn't published before every relocation unit reaches the point where its Message Follow route can be removed and each unit's cutover retransmission window ends, and neither judgment uses another node's clock.- Controlled ClientServer DEALER-ROUTER reply bytes appear in ordinary Core HWM accounting and total messaging, and don't appear in Completion fields. RouteMesh ROUTER-ROUTER reply bytes appear in Completion current, peak, and pending.
Topology status
- RouteMesh, ClientServer, and automatic fanout each provide readiness and target state as one complete status.
- Placement weight
0, capacity exhaustion, and recovery match public status. - Automatic fanout's 15-second record timeout only turns that publisher unavailable.
Observing changes
- Re-querying the current status after a
Sequencegap restores every state. - A slow observer, observation cancellation, and logger provider failure don't change dispatch, reply, or lifecycle terminal results.
Location query and log
- Object location lookup follows Location Runtime's page and cache contract.
- Publish target count and per-target accept/failure results don't appear in status or runtime structured logs.
Observability topic table of contents · Spec table of contents · Next: 02. Runtime Metrics