pub struct Supervisor<const N: usize> { /* private fields */ }Expand description
Orchestrates a set of managed tasks across spawn / teardown / bring-up.
Owned by a single supervisor task. Concurrent access from other tasks goes
through each TaskNode’s own atomic state, not the Supervisor struct.
Implementations§
Source§impl<const N: usize> Supervisor<N>
impl<const N: usize> Supervisor<N>
Sourcepub async fn run_pools(&self, spawner: Spawner)
pub async fn run_pools(&self, spawner: Spawner)
Drive the registered elastic pools (from GRAPH.pools) forever: run their
policies, then park until the next status signal (SCALE_REQ) or a pool’s
deferred deadline. Never completes — meant to be selected against the
application’s control / teardown futures in the supervisor task. When
another arm wins this future is dropped, which is safe: a half-applied
stop is re-driven on the next pass.
Source§impl<const N: usize> Supervisor<N>
impl<const N: usize> Supervisor<N>
Sourcepub const fn new(graph: &'static Graph<N>) -> Self
pub const fn new(graph: &'static Graph<N>) -> Self
Build a supervisor from a precomputed Graph — the GRAPH that
supervisor_graph! emits (node slots, dependency-index table, compile-time
topological order, and the elastic pools). A dependency cycle is a
compile error, so construction is infallible and does no work —
start / teardown / respawn_terminate just iterate.
Sourcepub async fn start(&self, spawner: Spawner) -> Result<(), SpawnError>
pub async fn start(&self, spawner: Spawner) -> Result<(), SpawnError>
Spawn every boot node in dependency order. Called once at boot.
Mode::OnDemand nodes are skipped — they’re brought up at runtime by
start_node. A parked node (no spawn fn) is spawned externally by
main() (with hardware handles main owns); it’s still marked running
here. Disabled nodes, and #[cfg]-ed-out slots, are skipped.
Async because an executor: NAME node first awaits its SpawnerSlot::ready
(bounded by SLOT_READY_TIMEOUT — the rendezvous with a tier or second core
that comes up asynchronously); a slot still empty at the deadline fails the
bring-up with SpawnError::Busy. A node with no executor: slot never
touches the timer.
Sourcepub async fn start_node(
&self,
node: &'static TaskNode,
spawner: Spawner,
) -> Result<(), SpawnError>
pub async fn start_node( &self, node: &'static TaskNode, spawner: Spawner, ) -> Result<(), SpawnError>
Start a single node at runtime — e.g. growing an elastic pool. Resets the
handle, spawns one instance via the node’s spawn fn (which must launch
exactly one), and marks it running. Returns SpawnError::Busy if the
underlying embassy task pool is exhausted (the ceiling), which the caller
treats as “can’t grow”.
Sourcepub async fn stop_node(&self, node: &'static TaskNode)
pub async fn stop_node(&self, node: &'static TaskNode)
Stop a single running node at runtime — e.g. shrinking an elastic pool.
Signals shutdown, waits for the ack, clears running. No-op if the node
isn’t running, or is detached (self-managed — the
supervisor never stops it). Panics if it doesn’t ack within the timeout.
Sourcepub async fn teardown(&self)
pub async fn teardown(&self)
Signal every running node to shut down in reverse topological
order, awaiting each node’s ack before moving to its dependency. Down
OnDemand nodes are skipped (no instance to ack). Pause-mode nodes ack
and park on wait_resume(); Terminate/OnDemand nodes exit. Panics if a
running node fails to ack within SHUTDOWN_ACK_TIMEOUT_MS.
Sourcepub fn resume_pausable(&self)
pub fn resume_pausable(&self)
Signal every Pause-mode node to resume. Cheap and synchronous — the tasks
were parked on wait_resume() and pick up immediately. Called separately
from respawn_terminate so the application can fire resume independently
of the respawn step. Disabled (manually-paused) nodes are skipped so a
manual pause sticks, and detached (self-managed) Pause nodes are left
parked; there is intentionally no dependency gate here.
Sourcepub async fn respawn_terminate(
&self,
spawner: Spawner,
) -> Result<(), SpawnError>
pub async fn respawn_terminate( &self, spawner: Spawner, ) -> Result<(), SpawnError>
Reset and re-spawn every Terminate-mode node in dependency order.
Pause-mode nodes are untouched (use resume_pausable); OnDemand nodes
are left down — they re-grow under load via start_node. Disabled nodes
are skipped so a manual stop sticks across the bring-up. Detached nodes are
skipped too: teardown never brought them down, so they are still running
and re-spawning would double-spawn them (see TaskNode::set_detached). The
reset happens before the spawn so newly-running tasks see a clean handle.
Source§impl<const N: usize> Supervisor<N>
impl<const N: usize> Supervisor<N>
Sourcepub async fn apply_control(&self, cmd: ControlCommand, spawner: Spawner)
pub async fn apply_control(&self, cmd: ControlCommand, spawner: Spawner)
Apply one control command, honoring pool membership and the dependency graph. Run from the supervisor’s driver loop (never concurrently with itself), so the cascade is atomic from the application’s perspective.