Interaction Model¶
Foundation topic index · Spec table of contents · Previous: 03. Framework Overview · Next: 05. Message Model
Defines how the target of a framework operation is selected, when the completion observed by the application occurs, and which owner performs the execution.
1. Common Model — Target Selection and Completion¶
The method of publishing one message to several remote nodes participating in the same Channel and to a local Spot is called Logical Multicast. The value the Location Store records for which node currently processes a global Spot or Actor is called authority.
| Model | Target selection | Completion the caller observes |
|---|---|---|
| node direct send | The caller directly specifies one RID belonging to the same MeshName — a name identifying one RouteMesh physical connection group. | Completes with no return data once the source-local queue accepts the message. |
| node direct request | The caller directly specifies one RID belonging to the same MeshName. | Completes with one of reply, timeout, or route error. |
| channel send | The framework selects one ready target from the RouteMesh — a scope in which multiple MeshNodes participate and exchange node and Channel messages — or ClientServer send paths registered under ChannelName — a name identifying the Channel scope a message is sent to. | Completes with no return data once the selected send path's source-local queue accepts it. |
| channel request | The framework selects one ready target from the RouteMesh or ClientServer send paths registered under ChannelName. |
Completes with one of reply, timeout, or route error. |
| Logical Multicast | The framework selects matching targets among ChannelName's remote members and local Spots. |
Completes with no return data once it secures a bounded worker and source-local capacity and starts the publish transaction. Doesn't wait for per-target submission or handler completion. |
| Spot message | The caller specifies a global Spot ID — a globally unique logical address identifying a Spot — and the framework finds the owner of the current Ready — the state where a Spot can receive application messages — authority. | Send completes with no return data after source-local queue acceptance; request completes with the reply result. |
| Actor message | The caller specifies a global Actor ID and the framework finds the current Ready authority's owner. | Send completes with no return data after source-local queue acceptance; request completes with the reply result. |
| Object create/get-or-create | The caller specifies a global ID and stable type, adding placement intent if needed. | Returns an ActorRef/SpotRef pointing at the created object, or a typed creation error. |
| classic fanout | The framework uses the ready subscriber set as the target. | Completes with no return data once the local publisher queue accepts it. |
| STREAM | The caller uses the connection identified by session RID. | A one-way packet completes with no return data after local queue acceptance; a request returns a reply. |
The method by which the framework picks one matching target in a Channel operation
is called select-one.
This table's "completion" is the completion boundary of each interaction model. The summary of message kinds (Send, Request, Logical Multicast, Classic fanout publish, STREAM send/request) and their completion conditions is defined by Message Model "2. Message Kinds And Completion".
2. The Public Interface That Starts an Interaction¶
The following table shows where the application starts each interaction. client
is obtained via DI or the current handler context — the application doesn't
directly select a transport socket or endpoint.
| Interaction | Starting interface | Target the caller specifies |
|---|---|---|
| Node direct/Channel select-one | IZLinkRouteClient |
Node direct: MeshName and target RID; Channel: ChannelName |
| Spot send/request | IZLinkSpotClient |
Global Spot ID |
| Actor send/request | IZLinkActorClient |
Global Actor ID |
| User Spot create/lookup | IZLinkSpotManager |
Stable Spot type and, if needed, global Spot ID |
| Actor create/lookup | IZLinkActorManager |
Global Actor ID and stable Actor type |
| Logical Multicast | IZLinkSpotPublisherClient |
ChannelName and topic |
| Classic fanout | IZLinkFanoutClient |
Fanout ChannelName and optional topic |
| STREAM send/reply | IZLinkSessionClient |
The current STREAM session — a server-side execution unit maintained from the time one STREAM client connection is accepted until it closes |
The code below is an explanatory declaration, abbreviated in .NET notation, to show the shape of a common interaction. It doesn't require the same signature in other languages — the precise per-language signature is owned by .NET Channel Messaging, .NET Spot, .NET Actor, and .NET STREAM Session.
public interface IZLinkRouteClient
{
// a direct operation where the caller specifies both Mesh and target node.
IZLinkSendCall SendToNode<T>(string meshName, RoutingId targetNodeRid, T message);
IZLinkRequestCall RequestToNode<T>(string meshName, RoutingId targetNodeRid, T request);
// a select-one operation where the framework picks one ready target for ChannelName.
IZLinkSendCall SendToChannel<T>(string channelName, T message);
IZLinkRequestCall RequestToChannel<T>(string channelName, T request);
}
public interface IZLinkSpotClient
{
// the framework finds the global Spot ID's current owner and sends.
IZLinkSpotSendCall SendToSpot<T>(string spotId, T message);
IZLinkSpotRequestCall RequestToSpot<T>(string spotId, T request);
}
public interface IZLinkActorClient
{
// the framework finds the global Actor ID's current owner and sends.
IZLinkActorSendCall SendToActor<T>(string actorId, T message);
IZLinkActorRequestCall RequestToActor<T>(string actorId, T request);
}
public interface IZLinkSpotPublisherClient
{
// publishes together to matching remote MeshNode and local Spot subscriptions.
IZLinkPublishCall Publish<T>(string channelName, string topic, T message);
}
public interface IZLinkSpotManager
{
// Create issues a new RID; GetOrCreate uses the RID the application specifies.
IZLinkSpotCreateCall Create(string spotType);
IZLinkSpotGetOrCreateCall GetOrCreate(string spotId, string spotType);
}
public interface IZLinkActorManager
{
// the Actor create family always takes a global Actor ID and stable Actor type together.
IZLinkActorCreateCall Create(string actorId, string actorType);
IZLinkActorGetOrCreateCall GetOrCreate(string actorId, string actorType);
}
public interface IZLinkFanoutClient
{
// builds a call to submit an event to the classic-fanout-only publisher transport.
IZLinkFanoutPublishCall Publish<T>(string channelName, string topic, T message);
}
public interface IZLinkSessionClient
{
// Send is a server-initiated packet; Reply is the current STREAM request's reply.
IZLinkSessionSendCall Send<T>(T message);
IZLinkSessionReplyCall Reply<T>(T message);
}
A Send... call waits up to local outbound admission via Async() and completes
with no return value. A Request... call waits for a reply via Async<TReply>().
Even in a language declaring Yield<TReply>(), this operation can only be used on
the shared turn of a SpotWide User Spot or Instance Spot.
3. Node Direct and Channel Select-One¶
Node direct uses the physical MeshName topology as-is, while channel
select-one layers a process-local logical address on top of it. We look at the
two layers separately.
%%{init: {'flowchart': {'nodeSpacing': 32, 'rankSpacing': 40, 'padding': 8, 'wrappingWidth': 180}, 'themeVariables': {'fontSize': '18px'}}}%%
flowchart LR
App[Application] -->|specifies meshName + target RID| Src[Source MeshNode]
Src -->|physical ROUTER connection, addresses directly by RID| Tgt[Target MeshNode]
%%{init: {'flowchart': {'nodeSpacing': 32, 'rankSpacing': 40, 'padding': 8, 'wrappingWidth': 180}, 'themeVariables': {'fontSize': '18px'}}}%%
flowchart LR
App[Application] -->|specifies ChannelName only| Sel{decide process-local<br/>send path}
Sel -->|RouteMesh| RM["one ready member<br/>with weight > 0"]
Sel -->|ClientServer| CS["one ready server"]
RM --> Submit[submit right after selection]
CS --> Submit
The physical diagram shows that node direct uses the actual ROUTER connection of the RID the caller specified, as is. The logical diagram shows that channel select-one only rides that physical connection after picking one from the process-local candidate pool. A channel call isn't fixed to any physical connection until the logical diagram's selection finishes.
- Node direct is used for infrastructure and explicit owner routing. If the
target RID isn't a current Mesh member, it ends with
NotFound; if it's a member but the pipe isn't ready, it waits up to the send-readiness limit and then ends withUnavailable. A Node direct operation doesn't automatically resend a failed request to a different node. - A global Spot/Actor message only uses a cached Ready route and a committed
Message Follow — the action of forwarding a
message that arrives at the previous owner node, on behalf of the new owner,
after relocation — route. If it can't relay to the current owner within the
Message Follow limit, it ends with
Unavailable, and the source doesn't read the Store and resubmit the same operation to a different owner. - A Channel operation first decides the process-local send path by ChannelName. A RouteMesh path picks one, with weight greater than 0, from the ready members at the moment of the call; a ClientServer path picks one from ready servers. No application callback sits between selection and submit.
- Weight 0 excludes it from new channel selection, and on RouteMesh also excludes it from Logical Multicast remote targets. It doesn't affect RID direct or an already-submitted operation.
- Immediately before starting the first binding operation, select-one picks one current eligible member of the same ChannelName. Once the binding operation starts, the selected target is fixed and Core owns HWM retry and completion. The framework neither reselects the target for capacity nor replays the operation. A direct call doesn't use this selection rule.
- Node direct keeps RID, Spot/Actor keeps global ID, and session keeps a binding token — physical peer lifecycle generation isn't exposed as public target identity.
- The same ChannelName can't be registered under multiple physical send paths. So the caller doesn't specify MeshName or ClientServer kind. Registering ChannelName under different topologies in the same process fails host startup as a configuration error.
- Node direct keeps using MeshName/RID. A Logical Multicast caller only specifies ChannelName and topic — the process-local channel index decides the owner RouteMesh's MeshNode. The selected owner MeshName is only observed in internal routing and runtime monitoring.
4. Send and Request¶
send is a one-way operation with no reply, and request is an operation that
completes with a reply or an error. Both calls can target a non-node-local
destination, so the timeout/route-error branch splits between the caller and the
remote owner.
%%{init: {'sequence': {'actorFontSize': '18px', 'messageFontSize': '18px', 'noteFontSize': '18px', 'boxMargin': 8, 'width': 140}, 'themeVariables': {'fontSize': '18px'}}}%%
sequenceDiagram
participant App as Application
participant Src as Source outbound queue
participant Tgt as Target owner
App->>Src: RequestToXxx(...).Async<TReply>()
alt source-local admission succeeds within send timeout
Src->>Tgt: builds reply correlation and delivers the request
alt reply arrives
Src-->>App: completes with the typed reply
else no response by request timeout, or route error
Src-->>App: completes with the matching framework error
end
else admission fails by send timeout
Src-->>App: completes with DeadlineExceeded (the send itself failed)
end
Note over Src,Tgt: Whichever path it ends on, the framework doesn't<br/>automatically resubmit the same request
sendprovides only a single async submit — it doesn't provide a synchronous terminator that tries once immediately. The return isn't confirmation that the destination handler ran — it indicates whether the framework accepted the message onto the local outbound queue.- If the queue is temporarily full, it waits for admission up to a finite send timeout. A one-way error occurring after acceptance is reported through the standard logger/telemetry provider configured by the application and through monitoring. The framework provides no dedicated runtime error sink.
- Global Spot/Actor send also uses the same async terminator. The source resolves the current Ready authority and completes the submit via local outbound admission. A cache hit also keeps the same public meaning, so it neither provides a synchronous submit depending on cache state, nor requires the caller to supply an owner node and generation.
- A message call doesn't create a Missing object's creation intent by default. Only when Instance intent is specified on a Spot-specific fluent call, and no Instance Spot is running, is a new Spot created and prepared to process the first message. This process is called cold activation. The starting method still only takes a global Spot ID — an optional stable type and initial Mesh are cold activation options on the fluent call.
- A valid one-way call completes with no return value once source-local admission, the source-side queue acceptance boundary, succeeds.
- If capacity isn't secured by the send timeout, it
completes with
DeadlineExceeded— a framework exception raised when an operation's completion condition isn't met by its allowed deadline. - A missing target/route and runtime shutdown complete with an operation-specific exception.
- Invalid argument/handle/state and a duplicate submit are also local exceptional completions.
- Cancellation is expressed as that language's cancelled awaitable.
- The framework never automatically resubmits the operation after any terminal completion.
requestbuilds reply correlation on the selected send path and delivers the terminal result exactly once. Request timeout is the time waiting for a reply, and send-stage backpressure is handled by send timeout. The framework doesn't automatically resend a request that ended in route error or timeout. Each language's transport error is converted into one of this document's closed framework results — a transport-specific result isn't exposed on the public call.- A request started from a Spot preserves the original activation and generation in the completion record. It doesn't re-dispatch the reply as a new application message. A request sent to a different RouteMesh or ClientServer Channel also follows the same single terminal-completion rule.
- Messages successfully submitted by the same origin to the same destination pipe are FIFO. A global order across different destinations, origins, or sessions isn't guaranteed.
The precise meaning of the common kinds returned by Send and Request, and of
timeout and cancellation, is defined by the
Framework Error Model.
5. Spot Logical Multicast¶
A Logical Multicast publish takes the target ChannelName, topic, and typed payload. At publish time it snapshots the remote MeshNode and local Spot matches.
- Submits a routed message once per remote MeshNode.
- The receiving MeshNode checks its local subscription for
(ChannelName, topic filter). - Matching Spot queues on the same node share a reference to immutable payload storage.
- Doesn't relay to a different MeshNode or replay a past event.
%%{init: {'sequence': {'actorFontSize': '18px', 'messageFontSize': '18px', 'noteFontSize': '18px', 'boxMargin': 8, 'width': 140}, 'themeVariables': {'fontSize': '18px'}}}%%
sequenceDiagram
participant App as Application
participant Exec as Bounded I/O executor
participant Rem as Remote MeshNode
participant Loc as Local Spot queue (same node)
App->>Exec: Publish(channelName, topic, message)
alt worker slot secured within send timeout
Exec-->>App: completes normally (no return data) — transaction starts
Note over Exec,Loc: the public call has already ended,<br/>per-target submission continues internally from here
Exec->>Rem: submits a routed message once per MeshNode
Rem->>Rem: checks local subscription for (ChannelName, topic filter)
Exec->>Loc: submits independently to matching local Spot queue
else worker slot not secured
Exec-->>App: DeadlineExceeded (transaction didn't start)
end
- The framework service runtime submits the publish transaction to a bounded
I/O executor. If a worker slot isn't secured by the send timeout, the
transaction doesn't start and it fails with
DeadlineExceeded. Once handoff succeeds and the transaction starts, the public terminal completes normally with no return data, and the runtime keeps submitting to each remote target and local Spot queue internally. - The transaction start is the commit point of the snapshot operation. Cancellation or shutdown doesn't stop processing of remaining targets. An earlier-accepted remote target or local Spot queue isn't canceled because a later target failed.
- It completes normally even if the snapshot has 0 targets. Remote unreachability, insufficient outbound capacity, and local Spot queue drops occurring after the transaction starts don't roll back already-accepted targets or retry the whole publish. Per-target accept/failure results aren't returned as a public result or aggregated into publish-only monitoring values.
- Publish's normal completion means the transaction started. It doesn't guarantee submission to the fixed snapshot's targets, Spot handler execution, subscriber receipt, or local Spot queue acceptance on the receiving MeshNode after the remote ROUTER accepts it.
6. Classic Fanout¶
Classic fanout is a publisher/subscriber channel independent of MeshNode. It only delivers a new event to a subscriber whose current connection and subscription are ready. The publisher doesn't store an event before connection or during a disconnection, and doesn't replay it after reconnecting.
- The publisher call provides only a single async terminator that waits for local admission up to the publisher socket's send timeout. Even with 0 subscribers, it completes normally with no return value once the local publisher queue accepts the event. This completion doesn't mean subscriber receipt or handler completion.
- Publish's common input is ChannelName, topic, and typed event. A convenience call using the typed event's packet name as the topic also builds the same operation. Both calls use the same publisher transport, timeout, and async completion rules; subscriber dispatch selects the handler by packet name and preserves topic in the handler context.
- The publisher publishes ChannelName and the actual endpoint to a dedicated location descriptor. An automatic subscriber connects to every live publisher for the same ChannelName and doesn't connect to a different ChannelName or a different descriptor kind. A manual subscriber only connects to the specified endpoint.
Logical Multicast and classic fanout both offer a publish/subscribe usage experience, but since their delivery targets and guarantees differ, they're registered as separate features.
7. Spot and Actor¶
A Spot is a logical mailbox owned by a MeshNode. Messages sent to that Spot pile up in the mailbox, and the framework takes them out one at a time and hands them to a handler.
Three Kinds of Spot¶
Spots come in three kinds, split by how they are created. The split governs the execution order and the Actor membership rules that follow, so it comes first. In familiar terms:
- Entry Spot — the place where Actors are born and destroyed. It is where a connecting player's Actor first sets foot, and where an Actor that has not joined any room yet stays. In a game this is the lobby; in a web service, the entry session right after login.
- User Spot — a place where several Actors gather and exchange messages. The application opens it when it needs one and closes it when it is done. In a game this is a game room; in a web service, a single collaborative document or chat room several participants have joined. Player Actors move here from the lobby and exchange messages inside the same room.
- Instance Spot — a place where no Actor lives. Use it when requests about one subject arrive from several places and must be lined up and handled one at a time. In a game this is ranking aggregation or a mailbox; in a web service, the place that handles the requests converging on a single order number without overlap.
The analogies are only aids. The contract is what the table and the sections below state.
| Kind | When to use it | Who creates it, and when | Do Actors belong to it? |
|---|---|---|---|
| Entry Spot | When you need a place to create and destroy Actors (lobby) | The framework creates it when the Object Server starts and issues the Spot ID. | Yes |
| User Spot | When several Actors must gather and exchange messages (game room) | The application creates it explicitly through the manager when needed. | Yes |
| Instance Spot | When requests on one subject must be handled in turn without overlap | No separate create call — it is prepared when the first message addressed to that Spot arrives. | No |
The exact creation API is owned by Entry Spot, User Spot, and Instance Spot, and the detailed comparison of the three kinds by Spot Model §3.
The Unit That Runs One Thing at a Time¶
An execution gate grants a callback authority to run now. The execution contract §2 owns sharing scope and turns by Spot kind; §3 owns gate release and Actor claims during Yield.
A Node handler does not read a Spot’s mailbox on its behalf. A Spot’s work runs on the Spot’s turn.
Creating a Missing Instance Spot by Message¶
A target Instance Spot that does not exist yet is created only when the Spot direct call states Instance intent. Without it, nothing is created.
Even when several nodes try to create the same Spot at once, only one actually does. The order is as follows.
- The one node that won creation rights from the Location Store runs the factory.
- That node confirms the first record in the durable activation inbox.
- It commits a location
Readycarrying the recovery root and cursor needed for recovery. - The framework restores the first record to the head of the local queue, then opens the activation barrier.
A node that loses the race takes the winner's result as is. It neither runs the factory separately nor re-sends the message.
ActorRef and SpotRef — A Snapshot of Where It Was¶
ActorRef and SpotRef are values that capture where the object was when it was looked up,
and they never change once created. They hold three things.
- the global ID
- ObjectGeneration — the number that distinguishes an object re-created under the same ID from the earlier one
- the
MeshNameandNodeRidat lookup time
They do not hold endpoints, internal frames, or runtime resources.
After an Actor moves to another node, reading a bound session's Ref/ref() again returns a
new value holding the same ActorId and ObjectGeneration with the MeshName and NodeRid of
the node it moved to. A value already obtained stays as it is — so a value kept around and used
later can point at the old location.
To send an ordinary message, specify the global ID, not this value. The framework finds which node currently holds the object at that moment.
How a Message Sent to an Actor Travels¶
An Actor message resolves the node that currently holds the Actor from the global Actor ID, then places the message directly in that Actor's mailbox. It does not pass through the Spot's message queue.
The execution turn follows the first table in §7 — an Entry Spot's Actors and a PerActor User
Spot's Actors each have their own turn, while a SpotWide User Spot's member Actors share a turn
with the Spot.
When an Actor handler must read or change state the Spot owns, it submits a separate send or request to the Spot. That work runs on the Spot's turn.
What Keeps Going While a Handler Waits¶
Completion handling for Node, Spot, and Actor calls and for binding operations keeps going even while an application handler is waiting on something. This handling happens in an execution area separate from the handler.
8. STREAM Session¶
A STREAM session owns connection lifecycle and packet order.
- The framework's internal recv loop puts a packet on a managed queue and then runs the session callback. The same session's packets and lifecycle callbacks run serially — a global order across different sessions isn't guaranteed.
- Once a Session and Actor are bound, session ingress submits complete messages to the Actor mailbox. A message an Actor sends to the client uses the current binding's session FIFO. During an Actor move, a session barrier distinguishes old-epoch from new-epoch order.
- The server package's bound session send, session Actor relay, and explicit STREAM send/reply also return the same async-only one-way admission result. A separate stream connector package's send builder follows the connector package's contract. A STREAM reply uses that STREAM socket's send timeout and doesn't use the caller's request timeout as the reply admission deadline.
- If the reply sequence or one-shot token is invalid, or the same reply call is submitted twice, it ends as a local exceptional completion. The first valid reply terminator atomically consumes the token before transport admission. Even if this terminator completes via backpressure, timeout, or cancellation, the token isn't reused. If two calls built from the same token race, only one starts transport admission.
Connection acceptance, registration, and dispatch context for a STREAM session are defined by STREAM Server Session; responsibilities during Session/Actor bind, rebind, and relocation are defined by Session And Actor Binding.
9. Representative Public Call Examples¶
The following code compares how the interactions from the previous sections
specify a target and which terminal method they end with. It doesn't require
the same signature in other languages — the precise signature is defined by each
language's per-language interface. routes, spots, actors, manager, and publisher
are public clients obtained via DI, and RID and ID are assumed already held by
the application. The business message types are illustrative examples.
9.1 Node Direct and Channel Select-One¶
// Node direct: the application specifies a particular node RID in the "world" Mesh.
await routes
.SendToNode("world", targetNodeRid, new ReloadConfig())
.Async(cancellationToken);
// Channel select-one: the framework picks one ready server in the "game" Channel.
MatchFound match = await routes
.RequestToChannel("game", new FindMatch(playerId))
.Timeout(TimeSpan.FromSeconds(2)) // upper bound for waiting on reply. Send admission is handled separately by send timeout.
.Async<MatchFound>(cancellationToken);
The first call doesn't pick a different node if the specified RID fails. The second call can pick a different eligible target under the same ChannelName only until one target accepts the operation.
9.2 Spot/Actor Messages and Creation¶
// Existing Spot: the framework finds the Spot ID's current Ready owner and sends the request.
RoomState room = await spots
.RequestToSpot(roomId, new GetRoomState())
.Timeout(TimeSpan.FromSeconds(1))
.Async<RoomState>(cancellationToken);
// Missing Instance Spot: only prepares the Spot when explicit intent is given, and processes the same first request.
ShardState shard = await spots
.RequestToSpot(shardRid, new LoadShard())
.InstanceSpot("world-shard") // starts cold activation only when this intent is present.
.InMesh("world") // initial Mesh for the newly created Instance Spot.
.Async<ShardState>(cancellationToken);
// A User Spot is either explicitly created via a manager call or joins an existing creation attempt.
ZLinkSpotCreateResult createdSpot = await spotManager
.GetOrCreate(roomId, "room")
.InMesh("world")
.Async(cancellationToken);
// An Actor message goes directly into the Actor queue without going through the member Spot's message queue.
PlayerState player = await actors
.RequestToActor("player-42", new GetPlayerState())
.Async<PlayerState>(cancellationToken);
// Actor creation specifies the global Actor ID and stable Actor type together.
// The result distinguishes an existing-Actor lookup, new-creation approval, and application decline.
ZLinkActorCreateResult actorCreation = await actorManager
.GetOrCreate("player-42", "player")
.InMesh("world")
.Async(cancellationToken);
A regular Spot/Actor message doesn't take a target node or endpoint. Even though
SpotRef and ActorRef have a NodeRid, it isn't used as a regular message's
address — the framework re-confirms the global ID's current authority.
9.3 Logical Multicast and Classic Fanout¶
// Logical Multicast: publishes together to matching remote nodes and local Spot subscriptions.
await spotPublisher
.Publish("world-events", "zone.7", new WeatherChanged("rain"))
.Async(cancellationToken);
// Classic fanout: targets subscribers currently connected on an independent publisher transport.
await fanout
.Publish("telemetry", "server.health", new HealthSample(cpu, memory))
.Async(cancellationToken);
Neither publish waits for handler completion. Per-target submission results aren't returned as a public result or aggregated into publish-only monitoring.
9.4 STREAM Session¶
// submits a server-initiated one-way packet to the current session FIFO.
await sessionClient
.Send(new ServerNotice("maintenance"))
.Async(cancellationToken);
// only consumes the current request's reply capability, exactly once, from within a STREAM request handler.
await sessionClient
.Reply(new LoginAccepted(playerId))
.Async(cancellationToken);
// bound Actor relay submits to the Actor mailbox using the current session binding.
await sessionActor
.RelayAsync(
ZLinkMessage.From(new ClientInput(sequence, command)),
cancellationToken);
Reply(...) isn't an API for sending an arbitrary server-initiated message. It
consumes the reply capability of the STREAM request the current handler received.
A regular server-initiated packet uses Send(...).
10. Handler Failure¶
- A request whose reply route can be restored completes with a structured error reply. A message whose reply route can't be restored, and a one-way message, are dropped, leaving a structured log and metric matching the cause.
- An application handler exception is also recorded as an error on the one-way path. A logger or telemetry-provider failure doesn't change the original reply or drop result.
11. How Termination Affects Interaction¶
New-work admission is a lifecycle decision separate from handler execution order.
Host relocation §14
owns the Shutdown host admission seal and the Relocate unit seal.
Feature-specific selection, placement, and existing-owner routing follow
§15 of that document.
This document therefore does not combine Relocating and Draining into one admission condition.
12. Verification Requirements¶
Using only the completion values returned by Send/Request/Publish/create
calls of the public client interfaces (IZLinkRouteClient, IZLinkSpotClient,
IZLinkActorClient, IZLinkSpotManager, IZLinkActorManager,
IZLinkSpotPublisherClient, IZLinkFanoutClient, IZLinkSessionClient),
verify the following. Each item maps to one test.
Target selection
- Node direct is sent only to the RID the caller specified, and doesn't automatically pick a different node even if that RID fails.
- Channel select-one picks one ready target at the moment of each call, and a member with weight 0 is excluded from new channel selection and from RouteMesh Logical Multicast remote targets.
- Registering the same ChannelName under different topologies (RouteMesh/ClientServer) fails host startup as a configuration error.
- A Spot/Actor message is delivered by resolving the current Ready authority
from the global ID, and the NodeRid held in
SpotRef/ActorRefisn't used as a regular message's address.
Completion
- A node direct send, channel send, Spot/Actor send, and STREAM one-way packet complete with no return data once the source-local queue accepts them.
- A node direct request, channel request, Spot/Actor request, and STREAM request complete with one of reply, timeout, or route error.
- Object create/get-or-create returns an
ActorRef/SpotRefpointing at the created object, or a typed creation error. - Logical Multicast publish and classic fanout publish complete with no return data solely on the publish transaction starting (or local publisher queue acceptance), without waiting for per-target handler execution or receipt — they complete normally even with 0 subscribers.
- Messages successfully submitted by the same origin to the same destination pipe arrive in FIFO order.
Failure
- If the queue is full and admission doesn't succeed by the send timeout, it
ends with
DeadlineExceeded. - The framework doesn't automatically resubmit a request that ended in route error or timeout.
- If a reply is submitted twice with the same reply token, the second call ends as a local exceptional completion.
- A request whose reply route can be restored completes with a structured error reply; a message whose reply route can't be restored, and a one-way message, are dropped and remain only as a log/metric. Public shutdown and relocation observations reference Host relocation verification requirements.
Foundation topic index · Spec table of contents · Previous: 03. Framework Overview · Next: 05. Message Model