88 lines
3.2 KiB
Rust
88 lines
3.2 KiB
Rust
//! Graceful shutdown pattern using announcement
|
|
//!
|
|
//! This example demonstrates how to use announcement to coordinate
|
|
//! graceful shutdown of multiple worker tasks.
|
|
//!
|
|
//! Run with: cargo run --example shutdown
|
|
|
|
use announcement::Announcement;
|
|
use std::time::Duration;
|
|
use tokio::time::sleep;
|
|
|
|
#[tokio::main]
|
|
async fn main() {
|
|
// Create shutdown signal channel
|
|
// The announcer will be used to broadcast the shutdown signal once
|
|
// The announcement can create multiple listeners for different tasks
|
|
let (shutdown_announcer, shutdown_announcement) = Announcement::new();
|
|
|
|
// Spawn three worker tasks, each with their own shutdown listener
|
|
let worker1 = tokio::spawn({
|
|
let shutdown = shutdown_announcement.listener();
|
|
async move {
|
|
println!("Worker 1: Starting");
|
|
loop {
|
|
// Check for shutdown signal without blocking
|
|
if shutdown.try_listen().is_some() {
|
|
println!("Worker 1: Received shutdown signal, cleaning up...");
|
|
sleep(Duration::from_millis(100)).await;
|
|
println!("Worker 1: Shutdown complete");
|
|
break;
|
|
}
|
|
|
|
// Simulate work
|
|
println!("Worker 1: Working...");
|
|
sleep(Duration::from_millis(200)).await;
|
|
}
|
|
}
|
|
});
|
|
|
|
let worker2 = tokio::spawn({
|
|
let shutdown = shutdown_announcement.listener();
|
|
async move {
|
|
println!("Worker 2: Starting");
|
|
loop {
|
|
// Use async listen() to wait for shutdown
|
|
tokio::select! {
|
|
result = shutdown.listen() => {
|
|
let _ = result; // Ignore whether it was announced or closed
|
|
println!("Worker 2: Received shutdown signal, cleaning up...");
|
|
sleep(Duration::from_millis(150)).await;
|
|
println!("Worker 2: Shutdown complete");
|
|
break;
|
|
}
|
|
_ = sleep(Duration::from_millis(300)) => {
|
|
println!("Worker 2: Working...");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
});
|
|
|
|
let worker3 = tokio::spawn({
|
|
let shutdown = shutdown_announcement.listener();
|
|
async move {
|
|
println!("Worker 3: Starting");
|
|
// This worker just waits for shutdown
|
|
let _ = shutdown.listen().await; // Ignore whether it was announced or closed
|
|
println!("Worker 3: Received shutdown signal, cleaning up...");
|
|
sleep(Duration::from_millis(80)).await;
|
|
println!("Worker 3: Shutdown complete");
|
|
}
|
|
});
|
|
|
|
// Let workers run for a bit
|
|
println!("Main: Letting workers run...\n");
|
|
sleep(Duration::from_secs(1)).await;
|
|
|
|
// Send shutdown signal to all workers
|
|
// This is a oneshot operation - can only happen once
|
|
// All three listeners will receive the signal simultaneously
|
|
println!("\nMain: Broadcasting shutdown signal...");
|
|
shutdown_announcer.announce(()).unwrap();
|
|
|
|
// Wait for all workers to complete graceful shutdown
|
|
let _ = tokio::join!(worker1, worker2, worker3);
|
|
println!("\nMain: All workers shut down gracefully");
|
|
}
|