use std::sync::Arc;
use std::sync::atomic::{AtomicU32, Ordering};
use std::time::Duration;
use taskvisor::prelude::*;
#[tokio::main(flavor = "current_thread")]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let one_shot: TaskRef = TaskFn::arc("one-shot", |_ctx: CancellationToken| async move {
println!("[one-shot] doing work...");
tokio::time::sleep(Duration::from_millis(200)).await;
println!("[one-shot] done.");
Ok(())
});
let attempt = Arc::new(AtomicU32::new(0));
let resilient: TaskRef = TaskFn::arc("resilient", move |_ctx: CancellationToken| {
let attempt = Arc::clone(&attempt);
async move {
let n = attempt.fetch_add(1, Ordering::Relaxed) + 1;
println!("[resilient] attempt #{n}");
tokio::time::sleep(Duration::from_millis(100)).await;
if n < 3 {
Err(TaskError::Fail {
reason: format!("attempt #{n} not ready yet"),
exit_code: None,
})
} else {
println!("[resilient] success on attempt #{n}!");
Ok(())
}
}
});
let cycle = Arc::new(AtomicU32::new(0));
let always_on: TaskRef = TaskFn::arc("always-on", move |_ctx: CancellationToken| {
let cycle = Arc::clone(&cycle);
async move {
let n = cycle.fetch_add(1, Ordering::Relaxed) + 1;
println!("[always-on] cycle #{n}");
tokio::time::sleep(Duration::from_millis(300)).await;
Ok(())
}
});
let specs = vec![
TaskSpec::once(one_shot),
TaskSpec::once(always_on).with_restart(RestartPolicy::Always {
interval: Some(Duration::from_millis(500)),
}),
TaskSpec::restartable(resilient)
.with_backoff(BackoffPolicy {
first: Duration::from_millis(200),
max: Duration::from_secs(5),
factor: 2.0,
..BackoffPolicy::default()
})
.with_max_retries(3),
];
let cfg = SupervisorConfig {
grace: Duration::from_secs(5),
..SupervisorConfig::default()
};
let sup = Supervisor::new(cfg, vec![]);
sup.run(specs).await?;
println!("All tasks finished.");
Ok(())
}