Skip to content

Feature flags

Reference

Only macros is on by default. Everything the supervisor can do is opt-in, including control and pool: both add code to the driver loop that runs every iteration whether or not a graph uses it. restart and bound-deps enable control on their own, so you rarely name it directly.

Using a gated construct without its feature is a compile error naming the feature, never a silent behavior change.

featuredefaultadds
macrosthe supervisor_graph! declaration macro
controlruntime control plane: ControlOp, request_control, try_request_control, apply_control; Deactivate holds dependents under the collateral flag until Activate releases them
poolelastic pools: ElasticPool, run_pools, GRAPH.pools
local-resourcesthe local resource kind. ⚠ opts into the macro emitting a documented unsafe impl Sync (one-executor contract, checked per slot)
fault-injectTaskNode::inject(Fault::{Stall, Wedge, Crash, Hog(..)}), clear_fault(), fault(): faults done to a task, not asked of its worker. A bench, test and demo feature
budgetthe divisible resource kind: a graph-sized Budget<K>, a Claimant per holder, allocator-side rebalance under a BudgetPolicy (FairShare, ShrinkFastGrowSlow), and a stopped holder’s share released by the supervisor (missed ack included; a Pause park keeps it)
readinessset_ready / wait_ready / clear_ready and the ready dep marker
livenessper-node heartbeat: beat(), ticks_since_beat(), is_stale()
liveness-monitorthe sweep: beat_timeout: / beat_window:, wait_health(), HealthEvent. Report-only. Implies liveness
epochsper-node activation generation: epoch(), wait_epoch_change(seen)
couplingdeclared dataflow: reads: / writes: and the signal-indexed queries; Stamped<T> for read-side write-freshness checks
coupling-observecouplingthe observed marker and its accessor; with liveness-monitor, beat drives the heartbeat and ready_on_write by polling
dataflowcouplingthe node as the access path: #[dataflow], discover, dataflow: [..], verbs of your own; beat_put / beat_writer (need liveness too)
graph-refthe graph as one addressable 'static (GraphRef); the handle data-deps and trace need
vetodataflowthe veto write marker: one contributor slot of a VetoGate<N> per writer, numbered and capacity-checked by the macro; node.veto(&SIG) moves only that writer’s bit, and a stopped writer’s bit stays asserted
data-depsgraph-ref + dataflowgated reads (Backed, the counted Open guard, retire, producer_of) and leases (Leased, lease, drain)
node-statusreport_status() / status(): a one-line self-description per node
restartSupervisor::restart: cycle a node and its transitive dependents, re-gated. Implies control
bound-depsthe bound dep marker: clear_ready() stops a bound dependent. ⚠ the one feature that changes a documented contract. Implies readiness + control
heap-statestate: Type = expr / state: zeroed Type. ⚠ emits a ~6-line fallible-boxing unsafe helper into your crate; needs a #[global_allocator]
defmtroute the supervisor’s logs through defmt
logroute them through the log facade (hosted/std). With neither, log calls are no-ops
tracetrace recorders: per-node CPU time, polls, max-poll watermark; executor stats; stall detection
trace-hooksalso define the _embassy_trace_* hook symbols at the graph site. Implies trace
metadata-namesnode names in task metadata for external tooling (rtos-trace/SystemView); no hook symbols
trace-namestrace + metadata-names
trace-nestedpreemption-exact accounting. Implies trace
trace-selfthe supervisor’s own driver task as a hidden auto-adopted node. Implies trace

A reasonable “most of the model” set for a connected device:

embassy-supervisor = { version = "0.8", features = [
"readiness", "liveness-monitor", "control", "pool",
"coupling-observe", "dataflow", "defmt",
] }