Skip to main content

Crate task_supervisor

Crate task_supervisor 

Source
Expand description

§task-supervisor

Crates.io Docs.rs

Keeps long-lived Tokio tasks alive. Restarts them with exponential backoff when they fail or panic, stops them cleanly, and lets you add, restart, kill or inspect them at runtime.

cargo add task-supervisor

§Example

use std::time::Duration;
use task_supervisor::{CancellationToken, SupervisedTask, SupervisorBuilder, TaskResult};

#[derive(Clone)]
struct Heartbeat;

impl SupervisedTask for Heartbeat {
    async fn run(self, cancel: CancellationToken) -> TaskResult {
        cancel.run_until_cancelled(async {
            loop {
                println!("beat");
                tokio::time::sleep(Duration::from_secs(1)).await;
            }
        }).await;
        Ok(())
    }
}

#[tokio::main]
async fn main() {
    let handle = SupervisorBuilder::new()
        .with_task("heartbeat", Heartbeat)
        .spawn();

    tokio::signal::ctrl_c().await.unwrap();
    handle.shutdown().await.unwrap();
}

examples/simple.rs shows restarts, runtime control and tracing output.

§How it works

           add_task / with_task
                    │
                    ▼
  ┌────────────► Running ──── Ok(()) ────► Completed
  │                 │
  │            Err / panic
  │                 │
  │                 ▼
  │            Restarting ── limit reached ──► Dead
  │                 │
  └─── backoff ─────┘

  kill / restart / shutdown on a Running task: Stopping, then Dead or a new Running
  • Each run gets a fresh clone of the registered task. Owned fields reset on every run; Arc fields are shared.
  • A failed run restarts after base_restart_delay * 2^n, capped at max_restart_delay, where n is the number of restarts in the current restart_limit window, minus a random jitter of up to restart_jitter. One restart too many and the task is Dead.
  • Stopping a task cancels its CancellationToken. The run has stop_timeout to return; then its future is dropped.

§Handling cancellation

Pick the cheapest that fits:

  • Ignore the token. run(self, _cancel: CancellationToken). Kill, restart and shutdown wait stop_timeout (5 s by default) before dropping the run. Nothing else changes.
  • cancel.run_until_cancelled(work).await as in the example. The run stops at its next .await, no cleanup.
  • tokio::select! on cancel.cancelled() when there is something to flush or close after cancellation. This is the only case that needs it.
  • Panics inside run are caught and count as failures.
  • Dropping the last SupervisorHandle shuts the supervisor down.

§Configuration

SupervisorBuilder methodDefaultMeaning
with_restart_limit(n, window)5 in 60sMax restarts within any window. with_unlimited_restarts() removes the limit.
with_base_restart_delay(d)1sDelay before the first restart in a window; doubles each time.
with_max_restart_delay(d)30sCap on the restart delay.
with_restart_jitter(f)0.1Shortens each delay by up to f of itself, at random. 0.0 disables.
with_stop_timeout(d)5sTime a cancelled run gets before being dropped.
with_dead_tasks_threshold(f)offShut down once dead / total >= f and at least one task is dead. Kills count.

§Runtime control

spawn() returns a SupervisorHandle, cheap to clone. Each request resolves when its effect is visible: add_task when the task is Running, kill_task when it is Dead, restart_task when the new run is Running. On a running task, kill_task and restart_task take up to stop_timeout.

MethodErrors
add_task(name, task).awaitTaskAlreadyExists, Closed
restart_task(name).awaitTaskNotFound, Closed
kill_task(name).awaitTaskNotFound, Closed
task_status(name).awaitTaskNotFound, Closed
task_statuses().awaitClosed
shutdown().awaitTooManyDeadTasks, Panicked, Aborted
wait().awaitTooManyDeadTasks, Panicked, Aborted

Closed: the supervisor has exited. Aborted: the Tokio runtime shut down under it. Panicked: a bug in this crate.

§Errors and logs

TaskError is Box<dyn Error + Send + Sync>, so ? works on any std::error::Error, anyhow::Error included.

Lifecycle events go through tracing: info for start/stop, warn for scheduled restarts and errors during cancellation, error for dead tasks. No subscriber, no cost.

Breaking changes are listed in the changelog.

§License

MIT

Structs§

CancellationToken
A token which can be used to signal a cancellation request to one or more tasks.
SupervisorBuilder
Configures and spawns a supervisor.
SupervisorHandle
Controls a running supervisor. Cheap to clone.

Enums§

SupervisorError
Why the supervisor exited abnormally. Returned by SupervisorHandle::wait and SupervisorHandle::shutdown.
SupervisorHandleError
Why a SupervisorHandle request was refused.
TaskStatus
Observable state of a supervised task.

Traits§

SupervisedTask
A long-lived unit of work managed by the supervisor.

Type Aliases§

TaskError
Error type returned by SupervisedTask::run.
TaskResult
Outcome of one run of a SupervisedTask.