tokio-task-manager
A crate which provides sync primitives with as main goal
to allow an async application making use of the Tokio runtime
to be able to gracefully shutdown, meaning that ideally the server process exits
only when all active tasks were done with their ongoing work.

Rust versions supported
v1.61.0 and above,
language edition 2021
.
Example
use std::time::Duration;
use tokio_task_manager::TaskManager;
#[tokio::main]
async fn main() {
let tm = TaskManager::new(Duration::from_millis(200));
let (tx, mut rx) = tokio::sync::mpsc::channel(20);
for i in 0..10 {
let tx = tx.clone();
let n = i;
let mut task = tm.task();
tokio::spawn(async move {
let mut child_task = task.clone();
let child_tx = tx.clone();
let m = n;
tokio::spawn(async move {
tokio::time::sleep(Duration::from_millis(m * 10)).await;
tokio::select! {
result = child_tx.send((m+1)*10) => assert!(result.is_ok()),
_ = child_task.wait() => (),
}
});
tokio::time::sleep(Duration::from_millis(n * 10)).await;
tokio::select! {
result = tx.send(n) => assert!(result.is_ok()),
_ = task.wait() => (),
}
});
}
let mut task = tm.task();
tokio::spawn(async move {
let mut child_task = task.clone();
tokio::spawn(async move {
tokio::select! {
_ = child_task.wait() => (),
_ = tokio::time::sleep(Duration::from_secs(60)) => (),
}
});
tokio::select! {
_ = task.wait() => (),
_ = tokio::time::sleep(Duration::from_secs(60)) => (),
}
});
tokio::time::sleep(Duration::from_millis(100)).await;
drop(tx);
assert!(tm.wait().await);
let mut results = Vec::with_capacity(20);
while let Some(n) = rx.recv().await {
results.push(n);
}
results.sort_unstable();
assert_eq!(
&results,
&[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100]
);
}
In case your application's root tasks are infinite loops you might wish
to gracefully shutdown only once a SIGINT (CTRL+C) signal has been received.
In this case you would instead of tm.wait().await
do instead
tm.shutdown_gracefully_on_ctrl_c().await
.
You can see this concept in action in the TCP Echo Server Example
includes with this crate. You can run it as follows:
cargo run --example tcp-echo-server
In another terminal you can connect to it using for example telnet
to see your own messages returned:
$ telnet 127.0.0.1 4000
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
hello
hello