//! Lazy initialization pattern using announcement //! //! This example demonstrates using announcement to signal when //! a resource is ready, allowing dependent tasks to wait. //! //! Run with: cargo run --example lazy_init use announcement::Announcement; use std::sync::Arc; use std::time::Duration; use tokio::time::sleep; #[derive(Debug)] struct DatabaseConnection { connection_string: String, pool_size: usize, } impl DatabaseConnection { async fn connect(connection_string: String) -> Self { println!("Database: Connecting to {}...", connection_string); // Simulate connection establishment sleep(Duration::from_millis(800)).await; println!("Database: Connection established"); Self { connection_string, pool_size: 10, } } fn execute_query(&self, query: &str) -> String { format!( "Query '{}' executed on {} [pool: {}]", query, self.connection_string, self.pool_size ) } } #[tokio::main] async fn main() { // Create announcement for database connection let (db_announcer, db_announcement) = Announcement::new(); // Multiple services that need the database let api_service = tokio::spawn({ let db_listener = db_announcement.listener(); async move { println!("API Service: Starting up..."); println!("API Service: Waiting for database connection..."); // Wait for database to be ready let db: Arc = db_listener.listen().await.unwrap(); println!("API Service: Database ready, processing requests"); let result = db.execute_query("SELECT * FROM users"); println!("API Service: {}", result); } }); let background_worker = tokio::spawn({ let db_listener = db_announcement.listener(); async move { println!("Background Worker: Starting up..."); println!("Background Worker: Waiting for database connection..."); let db: Arc = db_listener.listen().await.unwrap(); println!("Background Worker: Database ready, starting jobs"); let result = db.execute_query("UPDATE jobs SET status = 'running'"); println!("Background Worker: {}", result); } }); let metrics_collector = tokio::spawn({ let db_listener = db_announcement.listener(); async move { println!("Metrics Collector: Starting up..."); // Try polling first (non-blocking check) if db_listener.try_listen().is_none() { println!("Metrics Collector: Database not ready yet, waiting..."); let db: Arc = db_listener.listen().await.unwrap(); println!("Metrics Collector: Database ready"); let result = db.execute_query("INSERT INTO metrics VALUES (...)"); println!("Metrics Collector: {}", result); } } }); // Simulate initialization work before database connection println!("Main: Initializing application..."); sleep(Duration::from_millis(200)).await; // Now establish the database connection println!("\nMain: Starting database initialization...\n"); let db = DatabaseConnection::connect("postgresql://localhost:5432/myapp".to_string()).await; // Wrap in Arc for efficient sharing let db = Arc::new(db); // Announce that database is ready // All waiting services will be notified simultaneously println!("\nMain: Broadcasting database connection...\n"); db_announcer.announce(db.clone()).unwrap(); // Wait for all services to complete let _: (Result<(), _>, Result<(), _>, Result<(), _>) = tokio::join!(api_service, background_worker, metrics_collector); println!("\nMain: All services initialized successfully"); }