orbit-rs
orbit-rs is the primitive Orbit crate: a same-host runtime substrate
for recent facts shared by sibling processes.
It provides type-keyed bounded rings, optional POSIX shared-memory backing, fleet membership, cursor traversal, and native notification primitives.
orbit-rs is framework-agnostic. Application lifecycle and runtime
policy belong above this crate.
It is not a database, message broker, service process, global registry, or durable log.
Model
Fleet
process-local handle into a named fleet
OrbitTyped
Rust type -> stable KIND byte -> ring family
Ring / Frame
fixed-capacity append surface with bounded payloads
netid64::NetId64
runtime-bound id carried by every frame
Semantic layers
orbit-cache, orbit-event, orbit-lock, orbit-metrics
Frame identifiers come from the external
netid64 crate. Orbit uses that
runtime-bound identifier format; it does not define the identifier type
itself.
Fleet
Fleet is the per-process handle into Orbit.
Fleet::join(...)
-> process-local rings
Fleet::join_shm(...)
-> POSIX shared-memory surfaces visible to sibling processes
A fleet has a name, a NodeId, an expected fleet size, and shared
surface registries. Every OrbitTyped::KIND maps to its own ring and
declares its own RingSpec { capacity, payload_capacity, topology }.
Role hierarchy is
outside the crate: master, worker, standalone process, or sibling tool
can all join the same fleet if the embedder gives them compatible
configuration.
On Unix, shared-memory ring names are derived from:
/orbit-{fleet}-{kind}-{uid}
Rings
A ring is one or more fixed-capacity circular append lanes. The topology defines how writers publish:
Shareduses one lock-free multi-writer reservation counter;PerNodegives every fleet member an independent counter and disjoint slots;SharedOrdereduses one globally ordered counter, serializes the short write section with a process-recoverable kernel lock, and advances its head only after the slot commits.
Frames are written into:
counter % capacity
PerNode is a membership contract: only one active process may publish as
a given NodeId. Concurrent tasks inside that process are serialized locally.
An embedder that replaces a process must fully stop the old incarnation before
reusing its node id; workloads that genuinely have multiple writers use
Shared topology instead.
SharedOrdered is for algorithms whose correctness depends on one total
order. On Unix its advisory lock uses a state-free companion file at
/tmp/orbit-{fleet}-{kind}-{uid}.lock; all frame data remains in SHM. If a
writer process dies, the kernel releases the lock. A pre-head partial write
is then reused by the next writer instead of leaving a permanent hole.
The frame shape is:
id: NetId64 | frame kind: u8 | version: u64 | payload: bytes
Two kind values are intentionally present:
id.kind()
the OrbitTyped value family, used to choose the ring
frame.kind
the message/opcode class inside that ring
Readers must tolerate wraparound. If a reader asks for a counter whose
slot has already been overwritten, the frame is missing by design. For a
per-node ring, capacity is the retained message count per node lane.
Typed Rings
OrbitTyped is the type-to-ring contract. A Rust type declares a stable
KIND, and that KIND selects the ring family used for its frames.
use ;
Callers do not pass ring names through the API. They pass their own type.
Every worker built from the same program must know the same KIND and
RING_SPEC, so
Fleet::publish::<WorkerLoad> and Fleet::read_head::<WorkerLoad> meet
on the same ring.
OrbitTyped selects the ring; it does not serialize application values.
Semantic layers encode their own payloads before Fleet::publish::<T> and
decode frames returned by the fleet. Cache, event, lock, and metrics therefore
own their wire formats without a primitive-level serializer choice.
Cache Layer
Cache semantics live in the separate orbit-cache crate. It uses Orbit's
generic ring, cursor, shared-version, batch-publication, and notification
primitives to maintain a process-local L1 through dedicated mutation and
addressable payload rings.
orbit-rs deliberately does not expose a key/value cache API. This keeps the
primitive crate independent of cache eviction, TTL, resynchronization, and
payload-retention policy.
Event Layer
Topic framing, event cursors, and event bus semantics live in the separate
orbit-event crate. orbit-rs exposes the per-node
ring traversal and notification primitives that support it without knowing
about topics or application events.
Run the Linux suite natively on an Apple Silicon development host with:
On existing native Linux and FreeBSD checkouts, run the platform guard plus the shared smoke suite with:
Both commands delegate to just smoke. Gitea Actions targets the native Rust
runner registered by each Gitea instance and runs that shared recipe on every
push.
Typed dispatch, application lifecycle hooks, acknowledgements, durable replay, and consumer groups belong above the primitive and raw event layers.
Dependency Boundary
Application lifecycle, typed runtime adapters, handlers, process
supervision, and product policy should live above orbit-rs.