111 lines
3.6 KiB
Rust
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)
|
|
);
|
|
}
|