1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
//! # Dynamic
//!
//! Adds, removes, and cancels tasks while the supervisor is running.
//!
//! This is the pattern for applications where the set of tasks is not known at startup.
//!
//! *e.g., HTTP servers spawning a worker per request, job queues, or interactive CLIs.*
//!
//! ## Two modes of operation
//!
//! Taskvisor has two distinct entry points:
//!
//! | Method | When to use | Lifecycle |
//! |------------------------------------|------------------------|-----------------------------|
//! | `sup.run(specs)` | Tasks known upfront | Blocks until done or Ctrl+C |
//! | `sup.serve()` → `SupervisorHandle` | Tasks added at runtime | You control shutdown |
//!
//! ### `run()`: "Fire and forget"
//!
//! You know all your tasks at startup.
//!
//! The supervisor owns the lifecycle: it blocks, handles Ctrl+C, and shuts down automatically.
//!
//! Typical use cases:
//! - Microservice with a fixed set of background workers (metrics exporter, health checker, queue consumer)
//! - CLI tool that processes a batch of files in parallel
//! - Periodic cron-like jobs defined in config at startup
//!
//! ### `serve()`: "I'll manage it"
//!
//! Tasks appear and disappear at runtime.
//!
//! You get a `SupervisorHandle` and call `shutdown()` when you're done.
//!
//! Typical use cases:
//! - HTTP server that spawns a background job per request
//! - Plugin system where plugins register tasks dynamically
//! - Chat system where each connected user gets a dedicated task
//! - Job queue consumer that creates a task per incoming message
//! - Interactive CLI / REPL where user commands start/stop tasks
//!
//! ## What this shows
//!
//! - `sup.serve()`: starts listeners, returns a handle. Non-blocking.
//! - `handle.add(spec)`: register a new task dynamically.
//! - `handle.remove(name)`: cancel and deregister by name.
//! - `handle.cancel(name)`: cancel and wait for confirmation.
//! - `handle.list()`: snapshot of active task names.
//! - `handle.is_alive(name)`: check if a specific task is running.
//! - `handle.shutdown()`: graceful stop (consumes the handle).
//!
//! ## Runtime flavor
//!
//! We use `current_thread` here because a single-threaded runtime is enough for examples and tests.
//!
//! *It can be used with `#[tokio::main]` (defaults to multi-thread): taskvisor works with both.*
//!
//! ## Run
//!
//! ```bash
//! cargo run --example dynamic
//! ```
//!
//! ## Next
//!
//! | Example | What it adds |
//! |------------------------------|-------------------------------------------------|
//! | [`pipeline.rs`](pipeline.rs) | Admission control with the `controller` feature |
use Duration;
use *;
async