Skip to main content

control/
control.rs

1//! # Runtime Control Example
2//!
3//! Shows how to add, remove, and cancel tasks while supervisor is running.
4//!
5//! Demonstrates:
6//! - Adding tasks dynamically
7//! - Removing tasks by name
8//! - Checking task status
9//!
10//! ## Run
11//! ```bash
12//! cargo run --example control
13//! ```
14use std::{sync::Arc, time::Duration};
15use tokio_util::sync::CancellationToken;
16
17#[tokio::main(flavor = "current_thread")]
18async fn main() -> anyhow::Result<()> {
19    let sup = Arc::new(taskvisor::Supervisor::new(
20        taskvisor::SupervisorConfig::default(),
21        vec![],
22    ));
23    let runner = Arc::clone(&sup);
24    tokio::spawn(async move {
25        let _ = runner.run(vec![]).await;
26    });
27    sup.wait_ready().await;
28
29    // ============================================================
30    // Demo 1: Add task dynamically
31    // ============================================================
32    println!(" ─► Adding 'worker-A'...");
33
34    sup.add_task(make_worker("worker-A"))?;
35    tokio::time::sleep(Duration::from_secs(1)).await;
36    let tasks = sup.list_tasks().await;
37    println!(" ─► Active tasks: {tasks:?}");
38
39    // ============================================================
40    // Demo 2: Add second task
41    // ============================================================
42    println!(" ─► Adding 'worker-B'...");
43
44    sup.add_task(make_worker("worker-B"))?;
45    tokio::time::sleep(Duration::from_secs(1)).await;
46    let tasks = sup.list_tasks().await;
47    println!(" ─► Active tasks: {tasks:?}");
48
49    // ============================================================
50    // Demo 3: Remove specific task
51    // ============================================================
52    println!(" ─► Removing 'worker-A'...");
53
54    sup.remove_task("worker-A")?;
55    tokio::time::sleep(Duration::from_millis(500)).await;
56    let tasks = sup.list_tasks().await;
57    println!(" ─► Active tasks: {tasks:?}");
58
59    // ============================================================
60    // Demo 4: Cancel task (with confirmation)
61    // ============================================================
62    println!(" ─► Cancelling 'worker-B'...");
63
64    let cancelled = sup.cancel("worker-B").await?;
65    println!(" ─► Task cancelled: {cancelled}");
66
67    let alive = sup.is_alive("worker-B").await;
68    println!(" ─► Is alive: {alive}");
69
70    println!("Done");
71    Ok(())
72}
73
74fn make_worker(name: &'static str) -> taskvisor::TaskSpec {
75    let task: taskvisor::TaskRef =
76        taskvisor::TaskFn::arc(name, move |ctx: CancellationToken| async move {
77            println!("{:>4}[{name}] started", "");
78
79            let mut counter = 0u32;
80            loop {
81                if ctx.is_cancelled() {
82                    println!("{:>4}[{name}] cancelled", "");
83                    return Err(taskvisor::TaskError::Canceled);
84                }
85
86                counter += 1;
87                println!("{:>4}[{name}] tick #{counter}", "");
88                tokio::time::sleep(Duration::from_millis(500)).await;
89            }
90        });
91    taskvisor::TaskSpec::new(
92        task,
93        taskvisor::RestartPolicy::default(),
94        taskvisor::BackoffPolicy::default(),
95        None,
96    )
97}