pub struct DaemonRuntime { /* private fields */ }Expand description
Per-mesh compute runtime.
Holds the kind-keyed factory table, the per-daemon host registry,
and the Registering → Ready → ShuttingDown lifecycle gate. One
DaemonRuntime per Mesh; clone the handle freely — the inner
state is Arc-shared.
Implementations§
Source§impl DaemonRuntime
impl DaemonRuntime
Sourcepub fn new(mesh: Arc<Mesh>) -> Self
pub fn new(mesh: Arc<Mesh>) -> Self
Attach a runtime to an existing Mesh. Stage 1 does not
consume the Mesh — users keep their Arc<Mesh> for channel
registration, subscription, and the rest of the non-compute
surface. Stage 2 will install the migration subprotocol
handler when Self::start runs; until then inbound
migration messages (if any) are silently dropped by the core,
same as today.
Sourcepub fn register_factory<F>(
&self,
kind: &str,
factory: F,
) -> Result<(), DaemonError>
pub fn register_factory<F>( &self, kind: &str, factory: F, ) -> Result<(), DaemonError>
Register a factory for a daemon type. kind is a user-chosen
string shared across every node that may host this daemon.
Second registrations of the same kind return
DaemonError::FactoryAlreadyRegistered.
Valid in both Registering and Ready states; the runtime
permits new kinds to appear at runtime. Only ShuttingDown
rejects.
§Migration targeting
register_factory alone is not sufficient to accept
inbound migrations — it registers the kind-to-closure mapping
only on the SDK side. The core migration dispatcher looks up
factories by origin_hash (the daemon’s identity), not by
kind, because the migration wire protocol doesn’t carry a
kind string; the target couldn’t pick the right factory from
an inbound snapshot without an explicit binding.
To accept migrations for a specific daemon, the target must ALSO call one of:
Self::expect_migration(kind, origin_hash, config)— placeholder factory keyed byorigin_hash; the envelope on the snapshot supplies the keypair at restore time. This is the common case.Self::register_migration_target_identity(kind, identity, config)— pre-provisions the keypair as a fallback when the source migrates withtransport_identity: false.
Or spawn the daemon locally first (via Self::spawn);
spawn seeds both the SDK map and the core registry, so a
daemon that migrated out and migrates back in on the same
node is covered without extra calls.
Sourcepub async fn start(&self) -> Result<(), DaemonError>
pub async fn start(&self) -> Result<(), DaemonError>
Promote to Ready. Idempotent — a second call on an already-
Ready runtime is a no-op; a call on a ShuttingDown runtime
returns DaemonError::ShuttingDown.
Wires the migration subprotocol (0x0500) handler into the
mesh so inbound TakeSnapshot / SnapshotReady / etc.
messages reach the orchestrator / source / target handlers
owned by this runtime. Installing is idempotent w.r.t.
multiple start calls — the ArcSwapOption on the mesh
swaps the same handler in on each call.
Sourcepub async fn shutdown(&self) -> Result<(), DaemonError>
pub async fn shutdown(&self) -> Result<(), DaemonError>
Tear down the runtime. Unregisters every local daemon host,
clears the factory registry, and transitions state to
ShuttingDown. Subsequent calls on this runtime fail with
DaemonError::ShuttingDown. A second shutdown is a no-op.
Sourcepub fn simulate_not_ready(&self, flag: bool)
pub fn simulate_not_ready(&self, flag: bool)
Test-only. Force the readiness predicate seen by the
migration dispatcher to return false regardless of
lifecycle state — simulates a target that’s still in
Registering even after start() has run. Lets
integration tests exercise the NotReady retry path
without racing against runtime startup.
No effect on is_ready() or spawn / stop — those use
the underlying state directly. Only the dispatcher’s
readiness predicate is affected.
Sourcepub fn is_ready(&self) -> bool
pub fn is_ready(&self) -> bool
Readiness accessor for tests + operators. true iff the
runtime has transitioned to Ready and has not yet begun
shutting down.
Sourcepub async fn spawn(
&self,
kind: &str,
identity: Identity,
config: DaemonHostConfig,
) -> Result<DaemonHandle, DaemonError>
pub async fn spawn( &self, kind: &str, identity: Identity, config: DaemonHostConfig, ) -> Result<DaemonHandle, DaemonError>
Spawn a daemon of kind under the caller-provided
Identity. The identity’s keypair seeds the daemon’s
origin_hash + entity_id; the runtime registers both the
live host and a kind-keyed factory in the core registry so a
future migration target can reconstruct the daemon through
the existing DaemonFactoryRegistry::construct path.
The returned DaemonHandle is clone-safe; dropping it does
not stop the daemon. Call Self::stop explicitly.
Sourcepub async fn spawn_with_daemon<F>(
&self,
identity: Identity,
config: DaemonHostConfig,
daemon: Box<dyn MeshDaemon>,
kind_factory: F,
) -> Result<DaemonHandle, DaemonError>
pub async fn spawn_with_daemon<F>( &self, identity: Identity, config: DaemonHostConfig, daemon: Box<dyn MeshDaemon>, kind_factory: F, ) -> Result<DaemonHandle, DaemonError>
Spawn a daemon with a caller-supplied MeshDaemon instance,
bypassing the SDK-side kind-factory lookup.
Used by language-binding layers (currently: the NAPI compute
module) that build daemon instances via cross-FFI dispatch —
the factory closure for such a daemon can’t be a plain
Fn() -> Box<dyn MeshDaemon> because constructing the
daemon requires an awaitable call into the host language.
The binding does the await itself, hands in the resulting
Box<dyn MeshDaemon>, and this method does the rest of
what Self::spawn does: register the (origin_hash → kind-factory) mirror in the core registry so future
migrations can reconstruct the daemon, insert the host,
and run the same shutdown-race fence.
kind_factory is the closure the core registry stores for
migration-target reconstruction; it must be re-callable
(migration targets call it when they restore the daemon
on another node). Bindings typically build this by cloning
the same TSFN used for the initial spawn.
Sourcepub async fn spawn_from_snapshot_with_daemon<F>(
&self,
identity: Identity,
snapshot: StateSnapshot,
config: DaemonHostConfig,
daemon: Box<dyn MeshDaemon>,
kind_factory: F,
) -> Result<DaemonHandle, DaemonError>
pub async fn spawn_from_snapshot_with_daemon<F>( &self, identity: Identity, snapshot: StateSnapshot, config: DaemonHostConfig, daemon: Box<dyn MeshDaemon>, kind_factory: F, ) -> Result<DaemonHandle, DaemonError>
Spawn a daemon from a caller-supplied instance and restore its
state from snapshot, bypassing the SDK-side kind-factory
lookup. Parallels Self::spawn_with_daemon for restore.
Used by language-binding layers whose daemons are built via
cross-FFI dispatch — construction goes through the host
language, then the binding hands the built Box<dyn MeshDaemon>
(already wired to its TSFN bridge) plus the kind_factory
closure used by the core registry for migration-target
reconstruction.
Sourcepub async fn spawn_from_snapshot(
&self,
kind: &str,
identity: Identity,
snapshot: StateSnapshot,
config: DaemonHostConfig,
) -> Result<DaemonHandle, DaemonError>
pub async fn spawn_from_snapshot( &self, kind: &str, identity: Identity, snapshot: StateSnapshot, config: DaemonHostConfig, ) -> Result<DaemonHandle, DaemonError>
Spawn a daemon of kind and restore its state from snapshot.
The snapshot’s entity_id must match the caller’s
Identity; mismatch returns
DaemonError::SnapshotIdentityMismatch before any side
effects land.
Sourcepub async fn stop(&self, origin_hash: u64) -> Result<(), DaemonError>
pub async fn stop(&self, origin_hash: u64) -> Result<(), DaemonError>
Stop a daemon, removing it from the runtime’s registry. Valid
while Ready and (idempotently) during ShuttingDown —
ShuttingDown paths through here are a no-op because the
shutdown sweep has already drained the registry.
Sourcepub async fn snapshot(
&self,
origin_hash: u64,
) -> Result<Option<StateSnapshot>, DaemonError>
pub async fn snapshot( &self, origin_hash: u64, ) -> Result<Option<StateSnapshot>, DaemonError>
Take a snapshot of a running daemon by origin_hash. Returns
Ok(None) when the daemon is stateless.
Sourcepub fn deliver(
&self,
origin_hash: u64,
event: &CausalEvent,
) -> Result<Vec<CausalEvent>, DaemonError>
pub fn deliver( &self, origin_hash: u64, event: &CausalEvent, ) -> Result<Vec<CausalEvent>, DaemonError>
Deliver one causal event to the daemon identified by
origin_hash, returning the daemon’s outputs wrapped in the
host’s causal chain.
Stage 1 convenience — Stage 2 adds mesh-dispatched delivery via the causal subprotocol, and this direct path becomes testing sugar rather than the primary ingress.
Sourcepub fn daemon_count(&self) -> usize
pub fn daemon_count(&self) -> usize
Number of daemons currently registered.
Sourcepub fn migration_phase(&self, origin_hash: u64) -> Option<MigrationPhase>
pub fn migration_phase(&self, origin_hash: u64) -> Option<MigrationPhase>
Current orchestrator-side migration phase for origin_hash,
or None when no migration record exists (either never
started here or already reached its terminal state and was
removed). Useful for tests that assert the migration reached
true completion (record gone via ActivateAck) rather than
simply advancing to the Complete phase.
Sourcepub fn subscriptions(
&self,
origin_hash: u64,
) -> Result<Vec<SubscriptionBinding>, DaemonError>
pub fn subscriptions( &self, origin_hash: u64, ) -> Result<Vec<SubscriptionBinding>, DaemonError>
Snapshot the daemon’s subscription ledger — a cloned view of
every (publisher, channel) pair the daemon has subscribed
to via Self::subscribe_channel. Used by the migration
target path to drive replay and by tests / operators to
observe what a daemon is subscribed to.
Sourcepub async fn subscribe_channel(
&self,
origin_hash: u64,
publisher: u64,
channel: ChannelName,
token: Option<PermissionToken>,
) -> Result<(), DaemonError>
pub async fn subscribe_channel( &self, origin_hash: u64, publisher: u64, channel: ChannelName, token: Option<PermissionToken>, ) -> Result<(), DaemonError>
Subscribe a specific daemon to a channel on a remote
publisher. Routes through the mesh’s membership subprotocol
and records the subscription in the daemon’s ledger so
a migration target can replay it after cutover. Users should
use this method (rather than reaching through
rt.mesh().inner().subscribe_channel_*) for daemon-owned
subscriptions; otherwise the subscription travels with the
node, not the daemon, and silently drops on migration.
Flow:
- Hit the publisher’s membership endpoint via
Mesh::subscribe_channel_with_token(or the no-token variant). - On success, record
(publisher, channel) → SubscriptionBindingin the host’s ledger. - On wire failure, no ledger mutation.
token is the caller-owned PermissionToken for
token-gated channels; None for open channels.
Sourcepub async fn unsubscribe_channel(
&self,
origin_hash: u64,
publisher: u64,
channel: ChannelName,
) -> Result<(), DaemonError>
pub async fn unsubscribe_channel( &self, origin_hash: u64, publisher: u64, channel: ChannelName, ) -> Result<(), DaemonError>
Unsubscribe a specific daemon from a channel. Symmetric to
Self::subscribe_channel: mesh wire call first, then
ledger update.
Sourcepub fn register_migration_target_identity(
&self,
kind: &str,
identity: Identity,
config: DaemonHostConfig,
) -> Result<(), DaemonError>
pub fn register_migration_target_identity( &self, kind: &str, identity: Identity, config: DaemonHostConfig, ) -> Result<(), DaemonError>
Pre-register a factory on the target node keyed by the
daemon’s origin_hash, using the caller-supplied Identity
as the fallback keypair.
Use this when:
- The caller genuinely has the daemon’s keypair on hand
(typical: test harnesses that share the same
Identitybetween source and target runtimes). - Migration runs with
transport_identity = false, so the snapshot carries no envelope and the target needs a matching keypair pre-provisioned.
For the common envelope-transport case where the target
doesn’t know the daemon’s private key ahead of time,
prefer Self::expect_migration — it registers a
placeholder factory keyed only on origin_hash, and the
envelope in the migration snapshot supplies the real
keypair at restore time.
Sourcepub fn expect_migration(
&self,
kind: &str,
origin_hash: u64,
config: DaemonHostConfig,
) -> Result<(), DaemonError>
pub fn expect_migration( &self, kind: &str, origin_hash: u64, config: DaemonHostConfig, ) -> Result<(), DaemonError>
Declare on the target that this node expects a migration
for origin_hash of the given kind. Registers a
placeholder factory in the core registry — no matching
keypair required, because the migration snapshot’s
IdentityEnvelope
carries the real keypair and the dispatcher overrides the
placeholder at restore time.
Fails cleanly if the source migrates without an envelope
(e.g., MigrationOpts { transport_identity: false }) —
the target’s factory has no keypair and the dispatcher
emits IdentityTransportFailed. Use
Self::register_migration_target_identity with a shared
identity for the explicit public-identity-migration case.
Landing this method closes the seam documented in the
envelope_overrides_target_placeholder_keypair test of
Stage 5b of the identity-migration plan — targets can now
pre-register for a migration by origin_hash alone.
Sourcepub async fn start_migration(
&self,
origin_hash: u64,
source_node: u64,
target_node: u64,
) -> Result<MigrationHandle, DaemonError>
pub async fn start_migration( &self, origin_hash: u64, source_node: u64, target_node: u64, ) -> Result<MigrationHandle, DaemonError>
Start migrating a daemon from source_node to target_node.
The orchestrator runs on this node regardless of who owns
the daemon — call this on whichever node wants to drive the
migration state machine.
Returns a MigrationHandle whose MigrationHandle::wait
resolves when the migration reaches a terminal state
(Complete on success, MigrationError on abort / failure).
For the common local-source case (source_node == mesh.node_id()), the snapshot is taken synchronously inside
this call and SnapshotReady is shipped to the target. For
a remote source, the orchestrator sends TakeSnapshot to
the source and drives the rest of the state machine from
inbound wire messages.
Sourcepub async fn start_migration_with(
&self,
origin_hash: u64,
source_node: u64,
target_node: u64,
opts: MigrationOpts,
) -> Result<MigrationHandle, DaemonError>
pub async fn start_migration_with( &self, origin_hash: u64, source_node: u64, target_node: u64, opts: MigrationOpts, ) -> Result<MigrationHandle, DaemonError>
start_migration with caller-supplied options. Stage 6 of
DAEMON_IDENTITY_MIGRATION_PLAN.md:
lets the caller opt out of identity transport when the daemon
doesn’t need to sign anything on the target.
Trait Implementations§
Source§impl Clone for DaemonRuntime
impl Clone for DaemonRuntime
Source§fn clone(&self) -> DaemonRuntime
fn clone(&self) -> DaemonRuntime
1.0.0 (const: unstable) · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source. Read more