Capture task early returns and exit returns, with tokio
⚓ Rust 📅 2025-06-26 👤 surdeus 👁️ 19I'm trying to write an application using Tokio. The idea is to spawn to tasks that return anyhow::Result<>. The tasks should be stopped by a cancellation token if the user hits Ctrl+C.
A task returning early should result in the same behavior as if the user pressed Ctrl+C, with the addition of printing the task return value (A task shutting down early is suspicious, even if it returned Ok()).
At exit, when all tasks have been shut down, I also want to print any tasks returning Err().
The below code is basically what I have so far. Unfortunately, the TaskTracker swallows any errors returned at exit.
How should I structure this? I feel like there should be a standard way.
Thanks!
let ctrl_c = tokio::signal::ctrl_c();
let mut sig_term = tokio::signal::unix::signal(SignalKind::terminate())?;
let cancel_token = CancellationToken::new();
let tracker = TaskTracker::new();
let prober: JoinHandle<anyhow::Result<()>> = tracker.spawn(
prober(cancel_token.clone())
.instrument(info_span!("watcher_task")),
);
let cancel_clone = cancel_token.clone();
let signal_task = tracker.spawn(
signal_main(&config.signal, cancel_clone, song_update_rx)
.instrument(info_span!("signal_task")),
);
select! {
res = prober => {
error!("Watcher task early exit: {res:?}")
},
res = signal_task => {
error!("Signal task early exit: {res:?}")
}
_ = ctrl_c => {
info!("Received Ctrl+C (SIGINT)");
},
_ = sig_term.recv() => {
info!("Received SIGTERM");
},
}
info!("Waiting for tasks to exit");
cancel_token.cancel();
tracker.wait().await;
// Waiting without using the tracker, results in panic due to having used the futures multiple times
// if let Err(e) = prober.await? {
// error!("Prober exit error: {e}");
// }
// if let Err(e) = signal_task.await? {
// error!("Signal exit error: {e}");
// }
1 post - 1 participant
🏷️ rust_feed