Expand description
§task-supervisor
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;
Arcfields are shared. - A failed run restarts after
base_restart_delay * 2^n, capped atmax_restart_delay, wherenis the number of restarts in the currentrestart_limitwindow, minus a random jitter of up torestart_jitter. One restart too many and the task isDead. - Stopping a task cancels its
CancellationToken. The run hasstop_timeoutto return; then its future is dropped.
§Handling cancellation
Pick the cheapest that fits:
- Ignore the token.
run(self, _cancel: CancellationToken). Kill, restart and shutdown waitstop_timeout(5 s by default) before dropping the run. Nothing else changes. cancel.run_until_cancelled(work).awaitas in the example. The run stops at its next.await, no cleanup.tokio::select!oncancel.cancelled()when there is something to flush or close after cancellation. This is the only case that needs it.- Panics inside
runare caught and count as failures. - Dropping the last
SupervisorHandleshuts the supervisor down.
§Configuration
SupervisorBuilder method | Default | Meaning |
|---|---|---|
with_restart_limit(n, window) | 5 in 60s | Max restarts within any window. with_unlimited_restarts() removes the limit. |
with_base_restart_delay(d) | 1s | Delay before the first restart in a window; doubles each time. |
with_max_restart_delay(d) | 30s | Cap on the restart delay. |
with_restart_jitter(f) | 0.1 | Shortens each delay by up to f of itself, at random. 0.0 disables. |
with_stop_timeout(d) | 5s | Time a cancelled run gets before being dropped. |
with_dead_tasks_threshold(f) | off | Shut 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.
| Method | Errors |
|---|---|
add_task(name, task).await | TaskAlreadyExists, Closed |
restart_task(name).await | TaskNotFound, Closed |
kill_task(name).await | TaskNotFound, Closed |
task_status(name).await | TaskNotFound, Closed |
task_statuses().await | Closed |
shutdown().await | TooManyDeadTasks, Panicked, Aborted |
wait().await | TooManyDeadTasks, 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
Structs§
- Cancellation
Token - A token which can be used to signal a cancellation request to one or more tasks.
- Supervisor
Builder - Configures and spawns a supervisor.
- Supervisor
Handle - Controls a running supervisor. Cheap to clone.
Enums§
- Supervisor
Error - Why the supervisor exited abnormally. Returned by
SupervisorHandle::waitandSupervisorHandle::shutdown. - Supervisor
Handle Error - Why a
SupervisorHandlerequest was refused. - Task
Status - Observable state of a supervised task.
Traits§
- Supervised
Task - A long-lived unit of work managed by the supervisor.
Type Aliases§
- Task
Error - Error type returned by
SupervisedTask::run. - Task
Result - Outcome of one run of a
SupervisedTask.