A Unit is a compiled service definition. A Unit instance is one live state container for that definition. Keeping the terms separate is essential: many Unit instances can execute the same compiled methods, and none of them is the WebAssembly module instance that holds that code.
Four identities
| Identity | Scope | Purpose |
|---|---|---|
GroupId(u32) |
Program | selects a linked module and memory |
UnitId(u32) |
Program | selects a compiled Unit |
LocalInstanceId |
Store and Unit | selects one cached state container |
GlobalInstanceId |
runtime | combines Store, Unit, and local identity |
MethodId(u16) identifies a method within the relevant Unit ABI.
A UnitId stays stable when the same Program is regrouped. It must not be
derived from a group’s local position. Instance identities describe live
runtime state and are not stable business identifiers unless an application
stores such an identifier separately.
Compiled Unit
The Program’s Unit manifest describes:
- Unit identifier and link group;
- exported method table;
- placement policy;
- instance limits and eviction hints;
- initial arena policy;
- scheduler, debug, migration, and layout metadata.
The code and metadata are immutable for one Program version. Mutable state belongs to Store-local Unit instances.
Unit instance
The current runtime cache entry contains, conceptually:
UnitInstance
├─ UnitId + LocalInstanceId
├─ arena base, capacity, and generation
├─ root TCB offset
├─ invocation frame-region base
├─ host I/O slots and resources
├─ last-used time
└─ busy, shelved, or migration stateThe instance’s arena persists across invocations. A new invocation does not allocate a second Unit instance merely to obtain a fresh call stack. Instead, the runtime reuses the root task control block and establishes a temporary frame region within the existing arena.
Lifecycle
absent
│ first AnyOrSpawn invocation
▼
creating ──failure──▶ absent
│
▼
idle ◀──────────────┐
│ invocation │ completion
▼ │
busy ───────────────┘
│
├─debug stop──▶ shelved ──resume──▶ busy
├─migration───▶ moving ───────────▶ idle on peer
├─fault───────▶ poisoned ─────────▶ evicted
└─policy──────▶ evictedCreation allocates the arena and root TCB lazily. The TCB allocation survives for the instance lifetime, while its per-invocation fields are cleared and restamped before each entry.
Invocation setup
For every invocation the Store:
- selects or creates the target Unit instance;
- rejects reuse if it is busy, migrating, or shelved by the debugger;
- activates the Unit’s link group and arena globals;
- copies the encoded payload into the instance arena;
- resets and restamps the root TCB;
- records the temporary frame-region boundary;
- calls the compiled method entry;
- drives the trampoline until completion or suspension.
The v1 method entry receives:
(payload_abs: u32, payload_len: u32, root_tcb: u32) -> ()payload_abs is an absolute address into the active group memory for the
duration of entry. root_tcb is an arena-relative offset.
After successful completion, the temporary frame region is reclaimed. Values reachable from persistent Unit state remain in the arena.
Placement
Singleton
Singleton means one live logical instance for the Unit in the runtime node.
The first invocation chooses and pins a Store. Later invocations route to that
pin, and ordinary eviction does not discard the instance.
Singleton is node-local, not a cluster-wide distributed singleton. Cluster-wide leadership and replicated data have separate contracts described in Clustering.
A paused singleton remains the same logical state. The runtime must not create a second copy merely to route around its debugger stop.
Replicated
Replicated permits multiple instances distributed across eligible Stores.
The runtime uses round-robin Store selection, subject to:
- an optional
max_instances; - the availability of a reusable local instance;
- the eviction policy;
- inbox and Store liveness.
Current eviction hints are:
Never;- idle after a configured number of seconds;
- least recently used when pressure requires a victim.
Placement affects process-local execution capacity. It does not by itself replicate mutable Unit state or external database transactions.
Queuing
Each hosted Unit has a bounded Store inbox. Once an invocation has selected a busy instance, it joins that instance’s work queue. The instance still executes only one invocation at a time.
Callers choose their pressure behavior:
- use the nonblocking API to retain and retry or reject the invocation;
- await enqueue capacity;
- await the method’s full completion and receive its result.
Backpressure at enqueue is distinct from a method timeout after execution has begun.
Eviction
An idle replicated instance can be evicted under its policy. Eviction:
- removes the cache entry;
- releases its entire arena backing allocation;
- cancels or rejects remaining host operations as required;
- drops host resource slab entries;
- records the peak arena size for adaptive initialization.
Singletons and debug-shelved instances are not ordinary eviction candidates. A poisoned instance is force-evicted because its internal ownership state cannot be trusted.
Eviction can skip ordinary per-value destructors when the instance is poisoned. Applications must not use in-memory destructors as the sole mechanism for externally durable cleanup.
Migration
Migration is an exclusive transfer:
- stop new work for the instance;
- reach a quiescent safepoint;
- validate layout and Program compatibility;
- cancel or drain in-flight host operations;
- detach supported host resources;
- copy the arena;
- remove the source cache entry before publishing the destination entry;
- reattach resources and resume routing.
Unsupported resource kinds, active debugger suspension, pins, layout mismatches, or stored unstable function identities cause migration to be rejected. Rejection preserves correctness and allows the runtime to drain or recreate state through a different policy.
See Deployment for same-version migration and state-preserving redeploy.
State model
The runtime guarantees isolation of Unit-instance memory, not automatic persistence. State in the arena survives calls only while the instance remains live. It can disappear on eviction, process restart, failed migration, or incompatible redeploy.
Durable application state belongs in an explicit durable service such as a database or replicated log. Code should treat an instance arena as fast process-local state with defined execution isolation.
Invariants
- a Unit instance belongs to one Unit and one Store at a time;
- one instance has one persistent arena and host resource slab;
- at most one invocation mutates an instance;
- temporary frames do not define the lifetime of persistent Unit state;
- instance identity is never confused with Wasm
Instanceidentity; - migration never leaves the same mutable instance published on two Stores;
- singleton placement is node-local and does not imply Raft leadership.