Files
announcement/examples/config_broadcast.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

111 lines
3.6 KiB
Rust

//! Configuration broadcast pattern using announcement
//!
//! This example demonstrates broadcasting a configuration object
//! to multiple workers using Arc for efficiency.
//!
//! Run with: cargo run --example config_broadcast
use announcement::Announcement;
use std::sync::Arc;
use std::time::Duration;
use tokio::time::sleep;
#[derive(Debug, Clone)]
struct AppConfig {
database_url: String,
api_key: String,
max_connections: u32,
timeout_ms: u64,
}
#[tokio::main]
async fn main() {
// Create announcement for configuration
// We'll wrap the config in Arc to avoid cloning the data for each listener
let (config_announcer, config_announcement) = Announcement::new();
// Spawn multiple workers that need the config
// They can start before config is ready
let worker1 = tokio::spawn({
let config_listener = config_announcement.listener();
async move {
println!("Worker 1: Waiting for configuration...");
// Block until config is available
let config: Arc<AppConfig> = config_listener.listen().await.unwrap();
println!("Worker 1: Received config");
println!(" - Database: {}", config.database_url);
println!(" - Max connections: {}", config.max_connections);
// Simulate work with the config
sleep(Duration::from_millis(config.timeout_ms)).await;
println!("Worker 1: Completed work");
}
});
let worker2 = tokio::spawn({
let config_listener = config_announcement.listener();
async move {
println!("Worker 2: Waiting for configuration...");
let config: Arc<AppConfig> = config_listener.listen().await.unwrap();
println!("Worker 2: Received config");
println!(" - API Key: {}", &config.api_key[..8]);
println!(" - Timeout: {}ms", config.timeout_ms);
sleep(Duration::from_millis(config.timeout_ms)).await;
println!("Worker 2: Completed work");
}
});
let worker3 = tokio::spawn({
let config_listener = config_announcement.listener();
async move {
println!("Worker 3: Waiting for configuration...");
let config: Arc<AppConfig> = config_listener.listen().await.unwrap();
println!("Worker 3: Received config");
println!(" - All settings ready");
sleep(Duration::from_millis(config.timeout_ms)).await;
println!("Worker 3: Completed work");
}
});
// Simulate loading configuration (takes time)
println!("Main: Loading configuration...\n");
sleep(Duration::from_millis(500)).await;
// Create the configuration
let config = Arc::new(AppConfig {
database_url: "postgresql://localhost/myapp".to_string(),
api_key: "sk_live_abc123xyz789".to_string(),
max_connections: 100,
timeout_ms: 200,
});
println!("Main: Configuration loaded");
println!("Main: Broadcasting to all workers...\n");
// Broadcast config to all workers
// Using Arc means the data is only stored once
// Each listener gets a clone of the Arc (just incrementing ref count)
config_announcer.announce(config.clone()).unwrap();
// Verify original Arc still valid
println!("Main: Original config still accessible");
println!(" - Strong count: {}\n", Arc::strong_count(&config));
// Wait for all workers to complete
let _ = tokio::join!(worker1, worker2, worker3);
println!("\nMain: All workers completed");
println!(
"Main: Final Arc strong count: {}",
Arc::strong_count(&config)
);
}