Files
announcement/examples/lazy_init.rs
T
swaits e8e55b7676 chore: initial release v0.1.0
Runtime-agnostic oneshot broadcast channel for Rust.
2025-10-13 19:36:37 -06:00

114 lines
3.8 KiB
Rust

//! 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<DatabaseConnection> = 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<DatabaseConnection> = 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<DatabaseConnection> = 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");
}