Skip to content

Spot Model — Entry, User, Instance

Spot And Actor topic index · Spec table of contents · Next: 02. Spot Messaging

Defines what Entry Spot, User Spot, and Instance Spot have in common and how they differ. All three are Spots with an address and state, and all run callbacks in order, but their creation purpose, Actor membership — the relationship naming which Entry Spot or User Spot an Actor currently belongs to — and termination/ relocation contracts differ.

1. Spot Model Overview

This document answers "which Spot kind should I use?" and "what role does an Entry Spot play?"

A runtime node that sends or receives messages within a connection topology shared by multiple nodes is called a MeshNode. The following contracts are owned by other documents.

2. The Three Spots Differ in When They're Prepared and Their Purpose

%%{init: {'flowchart': {'nodeSpacing': 32, 'rankSpacing': 40, 'padding': 8, 'wrappingWidth': 180}, 'themeVariables': {'fontSize': '18px'}}}%%
flowchart LR
    Server["Object Server startup"] -->|"initialize the registered Entry Spot"| Entry["Entry Spot<br/>default membership for Actors"]
    Manager["Application manager call"] -->|"Create or GetOrCreate"| User["User Spot<br/>Actor container the application manages"]
    Message["first message with Instance intent"] -->|"prepared when the target is Missing"| Instance["Instance Spot<br/>message-processing unit with no Actor"]

An Entry Spot is prepared together with the Object Server. A User Spot is explicitly created by the application via a manager. An Instance Spot is prepared, with no separate create operation, when the first direct message needs it.

3. Similarities and Differences

Aspect Entry Spot User Spot Instance Spot
Primary purpose Manages the initial/default membership of Actors placed on that Object Server. A Spot the application explicitly creates; can manage Actor membership. Processes direct messages and timers with no Actor.
Registration/creation Registers a Spot implementation type on the Object Server builder; initialized at startup. Registers a factory for a stable type — a fixed name identifying the same kind of Spot across deployment versions or running nodes; created via manager Create/GetOrCreate. Registers a factory for a stable type; prepared by the first direct call carrying Instance intent — the caller's explicit choice that a new Instance Spot may be prepared when no target exists.
Spot ID — the global logical address identifying a Spot Issued by the framework. The format and conflict-handling rules are defined by MeshNode. Create has the framework issue it; GetOrCreate has the caller specify it. The caller specifies the target Spot ID of the direct message.
Stable type input No separate stable-type string is registered. A UTF-8 1-255 byte stable type is required. Uses a UTF-8 1-255 byte stable type. On Missing activation, either specify it or a single registered type is auto-selected.
Actor membership Supported. It's the initial membership of Actor creation and the target of JoinEntrySpot. Supported. An Actor can change membership via JoinSpot and leave. Not supported.
Direct packet Supported. Supported. Supported.
Timer and outbound call Supported. Supported. Supported.
Default execution mode Fixed Entry mode — see execution contract §2 SpotWide — see execution contract §2 Fixed Instance mode — see execution contract §2
Optional execution style Not provided. Factory registration can select PerActor. Not provided.
Relocation boundary Uses the per-Actor current-turn boundary. SpotWide uses an arbitrary safe turn boundary by default, or optionally only a boundary the application signals. PerActor uses the per-Actor current-turn boundary. Uses the current Spot turn boundary.
Logical Multicast subscription — delivering one message to multiple Spots on the same Channel by ChannelName and topic Supported. Supported. Not supported.
Explicit application close The Entry Spot context and manager don't provide a close operation. Passes the specified SpotRef to manager Close, or closes from the local context. Closes from its own handler or timer context.
Relocation The Entry Spot itself doesn't move. Moves an Actor as an independent relocation unit. SpotWide moves the whole Spot and member Actors at once. PerActor moves Actors independently without moving Spot state. Moves one Actor-less Spot as a relocation unit.
Host shutdown After cleaning up accepted turns, calls OnClosing with the HostShutdown reason. Applies the same shutdown closing contract. Applies the same shutdown closing contract.
.NET implementation type IZLinkEntrySpot; IZLinkEntrySpot<TActor> if an Actor type is specified IZLinkSpot; IZLinkSpot<TActor> if an Actor type is specified IZLinkInstanceSpot

The common stages of host relocation and the per-Spot-kind sequence diagrams are defined by Graceful Drain And Handoff §8.

The framework decides which queue to wait for execution on, based on the work's target. Direct packets and timer callbacks delivered to all three Spot kinds go into the Spot application queue. Business payload delivered to an Actor goes directly into that Actor's queue, without going through the Spot queue.

3.1 During Relocation, the Temporary Queue Is Checked First

Regular dispatch works as usual: it finds the execution queue of a Ready Actor or Spot and puts the message there. For a Ready Actor or Spot, creation, initialization, and its Location Store record are complete, so it can receive messages. The Location Store lets multiple nodes jointly confirm each Spot's current owner and state. Once the target runtime receives a Restore request, it registers a relocation temporary queue before dispatching the next packet. Afterward, Actor or Spot message dispatch order is as follows.

  1. Checks object kind, ID, and ObjectGeneration — a number distinguishing different incarnations of the same logical ID.
  2. Checks whether a temporary queue registered for the same RelocationId and target attempt exists.
  3. If so, puts it in the temporary queue without looking up the real application instance.
  4. If not, uses the existing object-lookup and execution-queue path.

The temporary queue can hold both messages relayed from the source ingress hold and messages arriving at the target before and after the owner change. The target doesn't run application payload from the temporary queue. Once Actor or Spot creation, state Restore, owner change, and needed lifecycle callbacks finish, it moves into the real execution queue in this order.

+----------------------------------------------------------------------+
| Target object queue                                                  |
|                                                                      |
| Restored work -> Temporary queue work -> New direct work             |
+----------------------------------------------------------------------+

This switchover is handled atomically with dispatch. Before the switch, every message the temporary queue accepted is put into the real queue first, then the temporary queue registration is removed. A message arriving concurrently goes into exactly one of the temporary queue or the real queue. The real queue doesn't run an application handler before this switchover finishes.

Saved-then-restored existing work is processed before the temporary queue's messages. Within the temporary queue, the order in which the target dispatcher accepted messages is preserved. No separate global order is created between messages arriving concurrently on different network routes.

In SpotWide User Spot relocation, the Spot and every member Actor are registered under the same relocation group. Each record in the temporary queue preserves the actual target Spot or Actor identity. Once restore finishes, Spot messages go into the Spot queue and Actor messages into that Actor's queue, preserving receive order within each target. In PerActor, since Spot and Actor relocation are registered independently, existing dispatch for an Actor not moving isn't blocked.

If the same Restore request arrives again, the existing temporary queue and Restore progress state are used. Messages aren't put into a previous target attempt's or a different ObjectGeneration's queue. Only on an explicit abort before relay-ready is accepted is the target temporary queue discarded without running and source-held work restored to the original queue. After that boundary, source isn't restored regardless of cutover-submit result. After owner commit, the temporary queue is only moved to the real queue while the same target process is running. If the target process terminates, a different runtime doesn't automatically take over this work.

The relationship between queues and gates follows execution contract §2. §16 owns Yield availability by call.

Entry Spot and PerActor User Spot use the same per-Actor unit model for relocation too. The Spot instance is an execution shell providing handlers and dependencies and doesn't own application state to keep after relocation. Only Actor state, Actor queue, and Actor timer move per Actor. State that must be shared across Actors is managed by the application in storage outside the node — Redis, a database, or a separate state service.

A Spot handler is created once and reused in the Spot activation scope; an Actor handler is created once and reused in the Actor activation scope. Different Actors in an Entry Spot or PerActor User Spot don't share a handler instance or scoped dependency. The creation/cleanup and relocation rules follow Framework API's Handler Lifetime.

A SpotWide User Spot isn't subject to this restriction. Since the Spot and member Actors form a single relocation aggregate, Spot fields and Spot timers can be moved together via the Spot relocation adapter.

3.2 Lifecycle Callback Per Spot Kind

The callback names in the following table use .NET notation. Other languages' names and async forms may differ, but the call condition and order are the same. Configure isn't an async lifecycle callback — it's the configuration stage that registers handlers — but it's included in the table to help understand the order in which a Spot instance is prepared.

Callback Entry Spot User Spot Instance Spot Purpose of the call
Configure O O O Registers the handlers that the Spot instance will use.
OnCreateAsync X O X When the manager creates a new User Spot, this callback checks the creation request and returns whether to accept creation and an optional reply. Not called for an Existing result that found an existing User Spot.
OnInitializeAsync O O O Finishes application initialization of the created Spot instance. Instance Spot uses this callback without OnCreateAsync.
OnClosingAsync O O O Cleans up application resources before a still-valid local Spot instance terminates. Call conditions are distinguished in §3.4.
OnActorJoinAsync X X When an existing Actor tries to move into a User Spot, the target User Spot approves or declines the request. Returning to an Entry Spot is default membership and doesn't use an admission callback.
OnJoinedActorAsync X Notifies the target Spot that a regular join's membership commit finished. Not called on initial Actor creation or maintenance restore.
OnLeaveActorAsync X Notifies the source Spot an Actor left, after the membership commit. Doesn't mean the Actor was destroyed.
OnDisconnectActorAsync X Notifies of a connection disconnect for an Actor belonging to that Spot.
OnCreateActorAsync X X Approves or declines a new Actor's initial Entry Spot membership and returns an optional reply. Distinguished from the regular join callback.

¹ Only applies to an Entry Spot or User Spot that specifies an Actor type and supports Actor membership.

3.3 Actor Membership Callbacks Run Separately on the Source and Target

Entry Spot and User Spot are different Spot instances. Even though both kinds implement the same Actor membership interface, the callback runs separately on the pre-move Spot and the post-move Spot.

For a join the application sends to a User Spot, the target User Spot approves the move via OnActorJoinAsync. Returning to an Entry Spot commits membership with no separate admission. In both cases, after commit, the target's OnJoinedActorAsync and the source's OnLeaveActorAsync run. So even if an Actor that was in a User Spot returns to an Entry Spot, the Entry Spot's OnCreateActorAsync and OnActorJoinAsync aren't called. The bidirectional callback comparison between Entry Spot and User Spot and the commit order are defined by Spot And Actor Membership §4.

3.4 The Callback Called When a Spot Instance Terminates

OnClosingAsync isn't a per-Actor callback — it's the terminal lifecycle callback of an Entry/User/Instance Spot instance. The framework passes the termination reason and absolute deadline when running the callback.

Value Termination reason Entry Spot User Spot Instance Spot Call condition
0 ExplicitClose X O O Called when the application starts a User/Instance Spot close, normally cleaning up that local instance.
1 HostShutdown O O O Called when the host cleans up a local Spot without relocation.
2 RelocationOut X O O Called after committing a User/Instance Spot owner to the target, cleaning up the source local instance.
3 IdleEvicted X X O Called when an Instance Spot exceeds the idle criterion and the local instance is evicted.

If a User Spot still has Actor membership and explicit close ends false, OnClosingAsync isn't called. A move of only a standalone Actor to a different Entry Spot also doesn't close the Entry Spot instance, so the Entry Spot's OnClosingAsync isn't called. On host shutdown, the callback runs while Actor membership and the local Spot instance are still valid, and scope and authority are cleaned up after the callback ends.

4. Entry Spot

4.1 The Object Server's Actor Entry Point

An Entry Spot is registered on a MeshNode with the Object Server role. The framework issues the Entry Spot ID and initializes the instance at startup. The Entry Spot isn't published to descriptor and resolver before initialization finishes. The Entry Spot ID's issuance rules, format, and conflict handling are owned by MeshNode.

When a new Actor is created, the Entry Spot of the owner MeshNode selected by the framework handles initial membership. Actor creation and initial Entry Spot membership finish within the same Ready barrier. Even though the Actor belongs to the Entry Spot, business messages are delivered to the Actor queue without going through an Entry Spot callback.

4.2 Entry Spot's Actor Lifecycle

An Entry Spot with an Actor type specified distinguishes the following three situations.

Situation Target Entry Spot Source Spot
A new Actor's initial membership Approve/decline via OnCreateActorAsync → membership/Ready commit on approval None
An application-requested regular JoinEntrySpot Commits membership with no admission callback → OnJoinedActorAsync After commit, source Entry Spot's or User Spot's OnLeaveActorAsync
Standalone Actor relocation for host maintenance Doesn't call an application membership callback. Doesn't call an application membership callback.

OnCreateActorAsync is only used when first placing a new Actor into an Entry Spot, and returns whether creation is approved and an optional reply. If declined, the staging Actor and reservation are cleaned up and it isn't exposed as Ready. OnCreateActorAsync and OnActorJoinAsync aren't called when an existing Actor returns from a User Spot or moves from a different Entry Spot via an application join.

A host Relocate moving a standalone Actor to a different node's Entry Spot isn't an application-requested membership change. The framework restores Actor state on the target and commits Actor owner and target Entry Spot membership, but doesn't call the target's OnJoinedActorAsync or the source's OnLeaveActorAsync. A dedicated relocation application callback also isn't provided.

Once state and queue are restored on the target and owner/membership are committed, queue merge, regular-route switch, and lifecycle finish before target Actor processing starts. If this Actor is bound to a Session, target runtime sends command 44 sessionRelocationRoute commit one-way to update the binding route — that Actor's current delivery path stored by the session owner — to the target owner. Along with the route switch, the current Actor location snapshot the bound-session accessor returns is also updated to the target's MeshName — a name identifying one physical connection group — and NodeRid, keeping the same ActorId/ObjectGeneration. The route and physical STREAM connection of a different Actor, bound to the same Session but not included in the relocation, don't change. Session owner validates that Session/binding/Actor generation match, along with relocation identity, submits held messages to target route, and releases the matching seal. There is no application reply; without that command 44 within SessionRelocationSealTimeout, it cleans the physical Session and related state. Target Actor processes messages without a command 44 application reply, and a message on the previous route is delivered by the Message Follow route — which forwards messages that reach the previous owner after an Actor or Spot has moved to a different MeshNode — to the new owner. A route update only applies to the same ObjectGeneration, and the application doesn't rebind to learn about the relocation. A new incarnation must be explicitly rebound by the application.

The application doesn't track the relocation via an Entry Spot lifecycle callback.

4.3 The Entry Spot Itself Doesn't Move

An Entry Spot belongs to that Object Server's lifecycle, so it isn't a relocation participant. Host Relocate moves an Actor belonging to an Entry Spot to the target node's Entry Spot, but doesn't move the source Entry Spot instance itself. The target Entry Spot is prepared by the framework with a new RID and lifecycle at target Object Server startup.

Since a standalone Actor move isn't an operation that closes the Entry Spot, the Entry Spot's OnClosing isn't called. When the host shuts down without relocation, after cleaning up accepted handler and timer turns, a HostShutdown closing context is delivered to the local Entry Spot.

5. User Spot

A User Spot is explicitly created by the application, which registers a stable-type factory and uses the manager.

  • Create has the caller specify a stable type, and the framework builds the global Spot ID.
  • GetOrCreate has the caller specify both the global Spot ID and stable type.
  • A User Spot supporting Actor membership serializes join/joined/leave/ disconnect control with its other callbacks on its own Spot queue.
  • If even one current Actor membership remains, public close ends false — the framework doesn't implicitly move or remove a member Actor.
  • SpotWide relocation preflights and commits the User Spot and the member Actors at seal time as one aggregate.
  • PerActor relocation prepares a stateless Spot shell on the target, moves Spot authority first, then moves member Actors as independent units.

A User Spot's default execution mode is SpotWide. Registration of the factory, application code creating a Spot instance for the registered stable type, can select PerActor. The mode is fixed before the MeshNode lifecycle starts and does not change while running. Mode-specific gates and Yield follow execution contract §2–§3.

5.1 SpotWide Relocation Boundary

The default for Spot relocation coordination mode is FrameworkManaged. In this mode, the framework picks a safe boundary after the current turn ends, so the application doesn't send a separate readiness signal.

A Spot that can only move once a round/match ends chooses ApplicationSignaled at factory registration. The application registers RelocationReady().Defer() at a safe turn and ends the handler. Starting a regular framework operation on the same turn after Defer() is InvalidOperation.

After the registered boundary, the framework briefly holds regular application jobs and handles one of the following.

Condition Handling owner Completion outcome
No relocation to use Current owner Continued
Relocation canceled before relay-ready is accepted The restored source owner Continued
Relocation completed Target owner Relocated

The framework calls OnRelocationReadyCompleted on the handling owner in the table before the next application job. For Relocated, target calls it after queue merge and regular-route switch but before dispatch opens; for Continued, source calls it before its next job. Once the callback completes, held messages and timers are processed again. The application can start the next round from this callback.

The callback is a no-op default implementation in the Spot interface. Choosing ApplicationSignaled doesn't force an override. In normal execution, each readiness registration creates one logical completion. If the process terminates while the callback is running, completion can't be confirmed, so recovery may call the same completion again. An override must be retry-safe.

Calling RelocationReady().Defer() on FrameworkManaged, PerActor, Entry Spot, or Instance Spot fails with InvalidOperation before a queue mutation and doesn't call the completion callback.

The generation-match check for creation request, placement, SpotRef, and close is defined by Spot Address Messaging.

5.2 User Spot Lifecycle

A new User Spot becomes Ready after the factory builds the instance and it goes through Configure, OnCreateAsync, and OnInitializeAsync. OnCreateAsync checks the creation request and returns whether to accept creation and an optional reply. A GetOrCreate that found a Ready User Spot of the same stable type and returned Existing doesn't run the factory or OnCreateAsync.

A User Spot supporting Actor membership runs OnActorJoinAsync and OnJoinedActorAsync when it's the target of a regular join, and OnLeaveActorAsync after commit when it's the source. An Actor disconnection is notified via OnDisconnectActorAsync. These callbacks run on the Spot lifecycle lane, following the User Spot's chosen execution mode.

When relocating a SpotWide User Spot to a different node, the Spot's and member Actors' logical membership is kept as-is. So Entry Spot's or User Spot's OnActorJoinAsync, OnJoinedActorAsync, and OnLeaveActorAsync aren't called for member Actors. When cleaning up the source User Spot instance, OnClosingAsync is called with reason RelocationOut.

When the relocation target rebuilds the User Spot instance, the factory creates the instance and then Configure and OnInitializeAsync run. There is no creation request, so OnCreateAsync does not run. OnInitializeAsync runs while the target admission seal still excludes external ingress, and the target becomes Ready only after that callback completes. This applies the §5.1 callback table's "completes the application initialization of a created Spot instance" to an instance recreated by relocation as well — skipping the initialization the application put there (an event replay, say) makes the target reach Ready in a different state from the source.

If a member Actor is bound to a Session, once the Spot and Actor are restored on the target and aggregate owner is committed, queue merge, regular-route switch, lifecycle, and dispatch opening finish before target runtime sends each Session owner command 44 sessionRelocationRoute commit one-way. The Session owner updates each Actor in the aggregate's binding route to the target owner. Along with the route switch, the current Actor location snapshot each bound-session accessor returns is also updated to the target MeshName/NodeRid, keeping the same ActorId/ObjectGeneration. The route and physical STREAM connection of an Actor bound to the same Session but not in this aggregate don't change. Each Session owner updates the binding once, submits held messages to target route, and releases the seal. There is no application reply; timeout cleans the physical Session. Target User Spot and member Actors process messages without a command 44 application reply. A route update only applies to the same ObjectGeneration, and the application doesn't rebind to learn about the relocation. A new incarnation must be explicitly rebound by the application.

PerActor relocation first prepares a private Spot shell on the target, using the same SpotId and ObjectGeneration. This shell doesn't accept application requests until the Location Store's Spot authority changes to the target. Once authority changes, new ToSpot, Actor Create, and Join are handled by the target, while the source shell only handles existing work and relocation control for Actors still remaining on the source.

Actors are each moved by the normal host scheduler, with no relocation-specific concurrent unit limit. An Actor's ObjectGeneration and logical User Spot membership are kept — only the Actor owner generation changes. Infrastructure relocation doesn't call OnActorJoinAsync, OnJoinedActorAsync, OnLeaveActorAsync, or OnDisconnectActorAsync. Once the last Actor and every already-accepted Spot work on the source are cleaned up, RelocationOut is delivered to the source shell and it terminates. If each Actor is bound to a Session, the target runtime sends command 44 sessionRelocationRoute commit one-way to update its binding route and bound-session current Actor location snapshot to the target owner and target MeshName/NodeRid, keeping the same ActorId/ObjectGeneration. There is no application reply or retransmission journal, and target Actor processes messages without a command 44 application reply. The application doesn't rebind for this update.

6. Instance Spot

An Instance Spot is a Spot with no Actor membership. It can use a direct packet handler, timer, and outbound call, but can't use the following.

  • Actor create/join/leave/relocation
  • Logical Multicast subscription
  • Manager Create/GetOrCreate

A Spot direct call — issuing a send or request by specifying one global Spot ID — by default, only finds a running Spot. To prepare an Instance Spot from a Missing RID, Instance intent must be specified on the same call. A regular message and Find don't start a hidden create. Cold activation preserving the first message, factory execution, and the Ready barrier are defined by Spot Address Messaging.

An Instance Spot can be closed by an application handler or timer from its own context. Host Relocate treats one Actor-less Spot as a relocation unit. Instance Spot callback execution and Yield follow execution contract §2–§3.

6.1 Instance Spot Lifecycle

Since Instance Spot doesn't support Actor membership, it doesn't provide Actor create/join/joined/leave/disconnect callbacks. In cold activation of a Missing Instance Spot, once the factory builds the instance, Configure and OnInitializeAsync run. It doesn't use the OnCreateAsync or empty creation request used for User Spot creation — instead, the first business message that started activation is preserved as the durable inbox's first record before Ready.

OnClosingAsync is called with reason ExplicitClose if the application normally closes it from its own context, HostShutdown if the host terminates without relocation, or RelocationOut if the source instance is cleaned up after a relocation commit.

6.2 Cleaning Up an Idle Instance Spot

The framework can clean up an Instance Spot based on an idle criterion. User Spot and Entry Spot aren't cleaned up — since a regular message doesn't create a nonexistent object (Spot/Actor Routing), a message arriving at a cleaned-up User Spot can't be revived and fails. An Instance Spot is recoverable on the next call even if cleaned up, since a call specifying Instance intent cold-activates it again.

Cleanup only starts when both of the following conditions are met together.

Condition Content
Idle time InstanceSpotIdleTimeout has passed since the last application work finished. The default is 0, meaning no cleanup.
No in-progress work The application queue and timer queue are empty, and there's no operation waiting for completion or relocation participation.

Cleanup calls OnClosingAsync with IdleEvicted, then evicts the local instance and removes the owner record from the Location Store. Since application state isn't preserved, state that needs to be kept must be saved by the application in OnClosingAsync.

An Instance intent call arriving after cleanup, under the same ID, cold-activates with a new ObjectGeneration. A regular message arriving after cleanup ends with NotFound.

7. Differences Visible in .NET

The following code is an excerpt of the three registration methods declared on the Object Server builder. Entry Spot only registers the implementation type, while User/Instance Spot register stable type and, per object kind, register options and relocation policy together in the factory configure callback. The callback must choose exactly one policy.

IZLinkMeshObjectServerBuilder AddEntrySpot<TEntrySpot>()
    where TEntrySpot : class, IZLinkEntrySpot;

IZLinkMeshObjectServerBuilder AddSpotFactory<TSpot>(
    string spotType,
    Action<IZLinkUserSpotFactoryBuilder<TSpot>> configure)
    where TSpot : class, IZLinkSpot;

IZLinkMeshObjectServerBuilder AddInstanceSpotFactory<TSpot>(
    string instanceSpotType,
    Action<IZLinkInstanceSpotFactoryBuilder<TSpot>> configure)
    where TSpot : class, IZLinkInstanceSpot;

The three Contexts share common identity, outbound call, timer, and worker functionality. Before calling the factory, the framework builds a Context combining MeshName, SpotId, ObjectGeneration, NodeRid, and owner fence. A User/Entry/Instance Spot the factory returns must expose the received Context as-is as a read-only member — returning a different Context means the staging Spot isn't exposed as Ready. A same-node operation keeps the Spot instance and Context. A cross-node relocation keeps SpotId and ObjectGeneration, passes a new Context, bound to the target owner generation, to the target factory, and fences new operations on the source Context after commit. A User Spot supports Actor leave and close; an Instance Spot only has close.

public interface IZLinkSpotCommonContext
{
    string MeshName { get; }
    string SpotId { get; }
    ulong ObjectGeneration { get; }
    RoutingId NodeRid { get; }
    IZLinkSpotOutbound Outbound { get; }

    ValueTask<IZLinkTimer> AddTimer<THandler>(
        string name,
        TimeSpan period,
        ZLinkTimerOptions? options = null,
        CancellationToken cancellationToken = default)
        where THandler : class;

    IZLinkWorkerCall<TResult> RunCpuWorker<TResult>(
        Func<CancellationToken, TResult> work);
    IZLinkWorkerCall<TResult> RunIoWorker<TResult>(
        Func<CancellationToken, ValueTask<TResult>> work);
}

public interface IZLinkSpotContext : IZLinkSpotCommonContext
{
    IZLinkSpotHandlerRegistry Handlers { get; } // direct and subscription handlers

    ValueTask LeaveActorAsync(
        IZLinkActor actor,
        CancellationToken cancellationToken = default);

    ValueTask<bool> CloseAsync(
        CancellationToken cancellationToken = default);
}

public interface IZLinkInstanceSpotContext : IZLinkSpotCommonContext
{
    IZLinkInstanceSpotHandlerRegistry Handlers { get; } // registers only direct handlers

    ValueTask<bool> CloseAsync(
        CancellationToken cancellationToken = default);
}

An Entry Spot provides Actor destroy and the full Spot handler registry instead of a close operation.

public interface IZLinkEntrySpotContext : IZLinkSpotCommonContext
{
    IZLinkSpotHandlerRegistry Handlers { get; } // direct and subscription handlers

    ValueTask DestroyActorAsync(
        IZLinkActor actor,
        CancellationToken cancellationToken = default);
}

The full interface and lifecycle callbacks are owned by the .NET Spot Interface.

8. Document Boundary

Document Detailed contract it owns
Spot Messaging Spot direct, Logical Multicast, queue admission, and dispatch
MeshNode Object role, Entry Spot ID and factory registration, placement capability
Spot And Actor Membership Actor creation, Entry/User Spot membership, and callback/commit order
Spot Address Messaging User/Instance Spot's ID, creation, cold activation, route, and close
Host Relocate, Shutdown And Handoff Shutdown, relocation, and recovery order for all three Spot kinds

9. Verification Requirements

The following is confirmed using only the public surface (Spot lifecycle callbacks, manager Create/GetOrCreate, and the relocation outcomes an application observes).

  • An Entry Spot's ID is issued by the framework at Object Server startup and only published after initialization.
  • Only the User Spot manager provides explicit Create/GetOrCreate.
  • A regular direct message and Find with no Instance intent don't create a Missing Instance Spot.
  • Entry/User Spot support Actor membership and Logical Multicast subscription; Instance Spot rejects both.
  • Actor business payload is submitted directly to the Actor queue without going through an Entry/User Spot callback.
  • The Entry Spot itself doesn't relocate — it's prepared with a new identity at target Object Server startup.
  • A User Spot moves as an aggregate with member Actors; an Instance Spot moves as a single, Actor-less relocation unit.

The verification requirements for the Entry Spot ID format, replacement lifecycle, and active conflict are owned by MeshNode "Implementation And Contract Test Verification Requirements".


Spot And Actor topic index · Spec table of contents · Next: 02. Spot Messaging