Skip to main content

TaskNode

Struct TaskNode 

Source
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 str

Human-readable name. Used in defmt logs and panic messages.

§mode: Mode

Lifecycle 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

Source

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.

Source

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!.

Source

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!.

Source

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!.

Source

pub fn shutdown_requested(&self) -> bool

True iff the supervisor has requested shutdown. Checked at the loop top alongside wait_shutdown() in a select.

Source

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.

Source

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.

Source

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.

Source

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.

Source

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.

Source

pub fn is_busy(&self) -> bool

True while this task is actively serving. Read by the scaling policy.

Source

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.

Source

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).

Source

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.

Source

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.

Source

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.

Source

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);
Source

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.

Source

pub fn task_id(&self) -> u32

The executor task id last recorded by set_task_id (0 = never spawned / not registered).

Source

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.

Source

pub fn poll_count(&self) -> u32

Number of executor polls of this node (wrapping counter).

Source

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.

Source

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).

Trait Implementations§

Source§

impl Debug for TaskNode

Manual impl: the private TaskHandle (Signals + atomics) has no Debug, and a snapshot of the live flags is more useful than raw handle internals anyway. finish_non_exhaustive marks the elided fields (spawn, the handle).

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.