pub struct TaskNode {
pub name: &'static str,
pub mode: Mode,
pub spawn: Option<fn(Spawner) -> Result<(), SpawnError>>,
/* private fields */
}Expand description
A node in the supervisor’s task graph.
Designed to live in static memory: every field is Sync, all constructors
are const. Declared by supervisor_graph!, which emits one per managed
task along with the Graph (GRAPH) that Supervisor::new consumes.
Fields§
§name: &'static strHuman-readable name. Used in defmt logs and panic messages.
mode: ModeLifecycle policy. See Mode.
spawn: Option<fn(Spawner) -> Result<(), SpawnError>>App-provided spawn function (typically an inline closure at the node’s
declaration). Called once at boot from Supervisor::start, again from
respawn_terminate for Terminate nodes, and at runtime from start_node
for OnDemand nodes. None for a parked node the application spawns
itself (e.g. a Pause sensor holding a peripheral handle): the supervisor
tracks its lifecycle but never spawns it.
Implementations§
Source§impl TaskNode
impl TaskNode
Sourcepub const fn new(
name: &'static str,
mode: Mode,
spawn: Option<fn(Spawner) -> Result<(), SpawnError>>,
disabled_at_boot: bool,
) -> Self
pub const fn new( name: &'static str, mode: Mode, spawn: Option<fn(Spawner) -> Result<(), SpawnError>>, disabled_at_boot: bool, ) -> Self
A single-instance node started at boot (Terminate/Pause) or on demand
(Mode::OnDemand). Every node is single-instance; an elastic service is
modelled as several OnDemand nodes of the same pooled task fn.
A TaskNode carries only its own identity and behaviour; the graph’s
dependency edges live in the compile-time index table that
supervisor_graph! emits and Supervisor::new consumes.
disabled_at_boot seeds the node’s disabled flag so a control-started node
(e.g. an OTA task) can be declared down and started later via a control op.
spawn is None for a parked node the application spawns itself.
Sourcepub const fn with_executor(self, slot: &'static SpawnerSlot) -> Self
pub const fn with_executor(self, slot: &'static SpawnerSlot) -> Self
Route this node’s spawn through the given executor SpawnerSlot (the
executor: NAME graph annotation). The supervisor awaits the slot before
spawning the node, so a tier filled late — or from another core — is handled
without a race, and the generated glue’s non-blocking get is already filled.
const and chainable in a static initializer; emitted by supervisor_graph!.
Sourcepub const fn with_resources(
self,
gates: &'static [&'static dyn ResourceGate],
) -> Self
pub const fn with_resources( self, gates: &'static [&'static dyn ResourceGate], ) -> Self
Declare the ResourceSlots this node’s spawn takes from (the
resources: graph clause). The supervisor awaits every gate being
filled before spawning the node, so the generated glue’s non-blocking
take() finds the value. const and chainable in a static
initializer; emitted by supervisor_graph!.
Sourcepub const fn with_ready_deps(self, deps: &'static [&'static TaskNode]) -> Self
pub const fn with_ready_deps(self, deps: &'static [&'static TaskNode]) -> Self
Declare the deps whose task-asserted readiness bring-up awaits before
spawning this node (the ready-marked subset of deps:). const and
chainable in a static initializer; emitted by supervisor_graph!.
Sourcepub const fn with_slot_timeout(self, timeout: Duration) -> Self
pub const fn with_slot_timeout(self, timeout: Duration) -> Self
Override the pre-spawn slot/gate wait bound for this node (the
slot_timeout: <millis> graph clause). The default
(SLOT_READY_TIMEOUT, 100 ms) assumes slots are provided before
start(); a node consuming a provider node’s outputs must cover the
provider’s async build time (the failure mode stays a loud
SpawnError::Busy, just later). const and chainable in a static
initializer; emitted by supervisor_graph!.
Sourcepub fn shutdown_requested(&self) -> bool
pub fn shutdown_requested(&self) -> bool
True iff the supervisor has requested shutdown. Checked at the loop top
alongside wait_shutdown() in a select.
Sourcepub async fn wait_shutdown(&self)
pub async fn wait_shutdown(&self)
Park until shutdown is requested. Returns immediately if shutdown has
already been requested. Use this for single-instance tasks in a select
against the task’s main work future.
Sourcepub fn ack_dropped(&self)
pub fn ack_dropped(&self)
Mark this instance as having shut down: clears the running flag and acks
the teardown handshake (so the supervisor’s wait_dropped completes).
Every instance must call this exactly once on exit (Terminate/OnDemand
mode) or on each pause (Pause mode). It also covers an autonomous exit
the supervisor didn’t request — e.g. a pool worker backing off — so the
pool sees the instance as down and can re-grow it under later demand.
Sourcepub fn mark_exited(&self)
pub fn mark_exited(&self)
Record that this node’s task body has returned. Called automatically
by the generated task: shell after the worker returns (and after
resource restores); call it manually at the end of a hand-written
spawn: task that can exit, where you would previously have called
ack_dropped alone. Idempotent, and subsumes
ack_dropped: it acks the teardown handshake and records completion,
so a body that returns on its own — the case the supervisor previously
could not observe — reads as down (is_running →
false, has_exited → true) instead of running
forever, and a control Activate can respawn it.
Sourcepub fn has_exited(&self) -> bool
pub fn has_exited(&self) -> bool
True once the last instance’s body returned — set by
mark_exited, cleared by the pre-spawn reset.
has_exited() && !shutdown_requested() distinguishes an autonomous
completion from an acked stop (the shutdown flag persists until the next
reset).
Sourcepub fn set_ready(&self)
pub fn set_ready(&self)
Assert readiness: “initialized and serving” (DHCP bound, registration
done, calibration finished) — the task-side half of a ready-marked
dependency edge. Distinct from running (spawned): deps: orders
spawns; a deps: [THIS ready] edge additionally awaits this call.
Latching until clear_ready or the pre-spawn
reset (a respawned provider re-asserts).
Sourcepub fn clear_ready(&self)
pub fn clear_ready(&self)
Withdraw readiness — status, not control: dependents are NOT stopped
or notified (pair with a control Deactivate for a cascade); it defers
future bring-up (a ready-marked dependent’s spawn, pool growth) until
set_ready again. Use for “link lost, still
reconnecting” style states.
Sourcepub fn is_ready(&self) -> bool
pub fn is_ready(&self) -> bool
True while the node asserts readiness. Pool growth checks this for
ready-marked deps; also useful in app health views.
Sourcepub async fn wait_ready(&self)
pub async fn wait_ready(&self)
Park until this node asserts readiness (immediately if it already has).
The supervisor’s bring-up is the intended pre-fill waiter; the latching
signal has the same single-pre-fill-waiter caveat as
SpawnerSlot::ready — for N concurrent app-side waiters fan out
through an app-owned embassy_sync::watch::Watch fed by the ready task.
Sourcepub fn beat(&self)
pub fn beat(&self)
Record a liveness heartbeat. Call once per work loop (or per served
request); an app watchdog task reads is_stale.
Sourcepub fn ticks_since_beat(&self) -> u32
pub fn ticks_since_beat(&self) -> u32
Ticks since the last beat (wrapping arithmetic; correct
for gaps under the u32 tick wrap, ~71 min at 1 MHz — far above any sane
max_age).
Sourcepub fn is_stale(&self, max_age: Duration) -> bool
pub fn is_stale(&self, max_age: Duration) -> bool
True when the node is running but hasn’t beaten within max_age — the
alive-but-wedged detector (a task hogging nothing, parked on an await
that will never complete). Not-running nodes are never stale: a stopped
or completed node is down, which is_running/has_exited already
report. Complements the trace stall watermark, which catches the
opposite failure (a poll that never yields).
Sourcepub async fn wait_resume(&self)
pub async fn wait_resume(&self)
Pause-mode only: park until the supervisor signals resume. Call after
ack_dropped — ack the pause, then park; held
resources stay owned across the park.
Sourcepub async fn run_cancellable<F: Future>(
&self,
fut: F,
) -> Result<F::Output, Aborted>
pub async fn run_cancellable<F: Future>( &self, fut: F, ) -> Result<F::Output, Aborted>
Race fut against this node’s shutdown: Ok(output) when the work
completes, Err(Aborted) when a stop/pause request wins. Owns the
select that rule 1 of the task protocol otherwise has you write by
hand. Does not ack — run your cleanup, then call
ack_dropped (or return through
run_cancellable_acked when there is no
cleanup between the select and the ack).
match node.run_cancellable(conn.serve()).await {
Ok(done) => handle(done),
Err(Aborted) => { flush().await; node.ack_dropped(); return; }
}Sourcepub async fn run_cancellable_acked<F: Future>(
&self,
fut: F,
) -> Result<F::Output, Aborted>
pub async fn run_cancellable_acked<F: Future>( &self, fut: F, ) -> Result<F::Output, Aborted>
run_cancellable that additionally calls
ack_dropped before returning Err(Aborted) — for
bodies with no teardown work between the select and the ack, e.g. a
runner whose drop is the cleanup:
let _ = node.run_cancellable_acked(runner.run()).await; // drop releases the pinsSourcepub fn mark_busy(&self)
pub fn mark_busy(&self)
Report that this task started serving a request (active). Fires the scale-request signal on a real idle→busy transition so the scaling policy can react (e.g. grow the pool); a redundant call doesn’t re-signal.
Sourcepub fn mark_idle(&self)
pub fn mark_idle(&self)
Report that this task finished serving and is idle again. Fires the scale-request signal on a real busy→idle transition so the scaling policy can react (e.g. shrink the pool); a redundant call doesn’t re-signal.
Sourcepub fn is_busy(&self) -> bool
pub fn is_busy(&self) -> bool
True while this task is actively serving. Read by the scaling policy.
Sourcepub fn is_running(&self) -> bool
pub fn is_running(&self) -> bool
True while the supervisor has this node spawned (and it hasn’t exited). Read by the scaling policy to count live instances, and by a task-state view.
Sourcepub fn is_disabled(&self) -> bool
pub fn is_disabled(&self) -> bool
True while the node is disabled: declared disabled in the graph
(stopped-at-boot, up on an explicit Activate), or manually deactivated
via the control interface and not yet re-activated. Read by a task-state
view and by the automatic bring-up paths (which skip a disabled node).
Sourcepub fn set_detached(&self, detached: bool)
pub fn set_detached(&self, detached: bool)
Mark/clear this node as detached: a self-managing node the supervisor
brings up once (via start) and then stops managing
entirely. Every runtime lifecycle operation skips a detached node: full
teardown, the control deactivate/activate cascades,
stop_node, respawn_terminate,
and pause-resume. It keeps running (or, for a one-shot, stays exited) across a
teardown/wake cycle instead of being stopped, re-enabled, or re-spawned. Use it
for a task that must outlive the teardown it participates in — e.g. a sleep/power
coordinator that tears the graph down, sleeps, then wakes it — or a self-managed
one-shot whose deps: exist only for start-ordering. The node owns its own
shutdown; the supervisor will not drive it.
Sourcepub fn is_detached(&self) -> bool
pub fn is_detached(&self) -> bool
True while this node is detached: self-managed, skipped by
every runtime lifecycle operation (teardown, deactivate/activate, stop_node,
respawn, pause-resume). Only the initial start brings it up.
Sourcepub fn set_task_id(&self, id: u32)
pub fn set_task_id(&self, id: u32)
Record the executor task id (SpawnToken::id() / TaskRef::id()) currently
backing this node, so the trace recorders can attribute executor polls to
it. Called automatically by the spawn glue supervisor_graph! generates;
call it manually only for a parked node (no spawn:) or a verbatim-closure
spawn:, where the macro cannot see the token. Overwrites on every (re)spawn.
Sourcepub fn adopt<S>(&self, token: &SpawnToken<S>)
pub fn adopt<S>(&self, token: &SpawnToken<S>)
Register an externally-spawned token as this node’s live task: records
the task id for the trace recorders and (feature metadata-names)
stamps the node name into the task Metadata. One call replaces the
manual set_task_id dance wherever the macro can’t
see the token — parked nodes and verbatim-closure spawn: forms:
let t = environment_task(i2c_dev)?;
BME280.adopt(&t);
high_spawner.spawn(t);Sourcepub fn stamp_name<S>(&self, token: &SpawnToken<S>)
pub fn stamp_name<S>(&self, token: &SpawnToken<S>)
Stamp this node’s name into the task’s embassy Metadata (feature
metadata-names), so external consumers — rtos-trace/SystemView, debuggers —
show the graph node name instead of an opaque task id. Unlike
adopt this does not capture the task id or touch the
supervisor’s trace recorders, so it needs neither the trace feature nor
the _embassy_trace_* hook symbols: it is the name-only spawn path emitted
when metadata-names is on but trace is off (pair it with embassy’s
rtos-trace). Called automatically by the spawn glue; call it manually only
for a parked or verbatim-closure node the macro can’t see.
Requires embassy-executor’s metadata-name feature, which metadata-names
pulls in; without a registered name the task keeps embassy’s default.
Sourcepub fn task_id(&self) -> u32
pub fn task_id(&self) -> u32
The executor task id last recorded by set_task_id
(0 = never spawned / not registered).
Sourcepub fn exec_ticks(&self) -> u32
pub fn exec_ticks(&self) -> u32
Accumulated executor-poll time of this node, in embassy-time ticks. Wrapping:
sample twice and wrapping_sub the readings to get a rate over a window.
Sourcepub fn poll_count(&self) -> u32
pub fn poll_count(&self) -> u32
Number of executor polls of this node (wrapping counter).
Sourcepub fn max_poll_ticks(&self) -> u32
pub fn max_poll_ticks(&self) -> u32
Longest single executor poll of this node ever observed, in ticks — the “never yields” watermark. A poll is expected to be microseconds; a large value names the node that hogged its executor, even after the fact.
Sourcepub fn set_disabled(&self, disabled: bool)
pub fn set_disabled(&self, disabled: bool)
Set/clear the manual-deactivation flag. Set by Supervisor::deactivate,
cleared by Supervisor::activate. Deliberately not touched by
reset(), so a manual stop survives respawn cycles and RAM-retaining
power-state transitions.
Public so an application can pre-disable a Terminate node before
Supervisor::start, making it a stopped-at-boot task that only comes up on
an explicit Activate control (a node started by control rather than at boot).