Skip to main content

task

Attribute Macro task 

Source
#[task]
Expand description

This decorator macro replaces embassy_executor::task to create an async task that can be monitored by the task-watchdog.

§Arguments

  • timeout: The duration to wait for a feed before considering the task stalled (e.g. timeout = Duration::from_millis(2000))
  • setup: Whether this task contains setup code before the main loop (defaults to false). If true, the macro will split the function body into a setup part (before the first loop) and a consume part (from the first loop onward), and will only register the watchdog and apply the timeout to the consume part. This allows for longer-running setup code without triggering a false positive stall detection, while still monitoring the main loop of the task. A task with setup = true must contain at least one loop statement (e.g. loop { ... }) for the macro to split on, and the user is expected to feed the watchdog inside the loop(s) to indicate the task is still alive.
  • keep: Whether to keep the task descriptor after the task finishes (defaults to true). If keep is false, the task will be deregistered upon completion. A task with keep = true should not be fallible.
  • fallible: Setting this to true will remove the requirement for the task function to return ! (never), and allow it to return normally. This is useful for tasks that may need to exit on their own after some condition is met, rather than running indefinitely. A fallible task will still be monitored by the watchdog until it finishes, and crash the program. Set keep = false for a fallible task to deregister itself from the watchdog when it finishes.
  • retries: The number of times to retry feeding the watchdog before considering the task stalled (defaults to 0). This is useful for allowing some number of missed feeds before triggering a stall, which can help reduce false positives in cases where occasional delays are expected (e.g. retries = 3 will allow 3 missed feeds before considering the task stalled). By default, the watchdog will consider the task stalled immediately upon a missed feed.

§Function Requirements

  • The function must be async and return ! (never), unless fallible = true is set, in which case it can return normally.
  • The function must have at least one parameter of type embassy_task_watchdog::TaskWatchdog, and the first parameter must be an identifier pattern (e.g. wd: TaskWatchdog). The macro will convert this into a per-task bound watchdog (embassy_task_watchdog::BoundWatchdog) that the user can feed to indicate the task is still alive.
  • If setup = true is set, the function must contain at least one loop statement (e.g. loop { ... }) for the macro to split the setup and consume parts. Any code before the first loop will be considered setup code that runs once. The setup code should not be in a block (surrounded by {}).
  • If keep = false is set, the function should not be fallible, since it will deregister itself from the watchdog when it finishes, and won’t be around to feed it anymore - which will lead to timing out the watchdog.

§Examples

§Simple Example

Example usage for a task is shown below, that feeds the watchdog every 1000ms and is considered stalled if it goes more than 2000ms without feeding:

#[task(timeout = Duration::from_secs(2))]
async fn my_task(watchdog: TaskWatchdog) {
    loop {
      watchdog.feed().await; // Feed the watchdog to indicate the task is still alive
       // Do some work
       Timer::after(Duration::from_secs(1)).await;
    }
}

§Setup Mode Example

#[task(timeout = Duration::from_secs(2), setup = true)]
async fn my_task_with_setup(watchdog: TaskWatchdog) {
    // Some setup code that runs once
    do_setup().await;
    loop {
        watchdog.feed().await; // Feed the watchdog to indicate the task is still alive
        // Do some work
    }
}

§Fallible Task Example

#[task(timeout = Duration::from_secs(2), fallible = true, keep = false)]
async fn my_fallible_task(watchdog: TaskWatchdog) {
    loop {
        watchdog.feed().await; // Feed the watchdog to indicate the task is still alive
        // Do some work
        if some_condition() {
            return; // Exit the task normally, which will deregister it from the watchdog since keep = false
        }
    }
    // task is deregistered here, since keep = false, so the watchdog will stop monitoring it
    // and won't trigger a system reset.
}

§Caution

In release builds, the macro checks that the number of tasks does not exceed the configured limit (defaults to 32, refer to embassy_task_watchdog_numtasks::MAX_TASKS), and will produce a compile error if more tasks are defined. In debug builds, this check is skipped to allow for continuous integration testing without needing to adjust the limit.