Files
mytheclipse/crates/mytheclipse/examples/high_level.rs
T

135 lines
4.6 KiB
Rust

//! End-to-end demo of the high-level (round 7-15) abstractions in `mytheclipse`.
//!
//! Run with: `cargo run -p mytheclipse --features full --example high_level`
//!
//! Demonstrates, wired together in one realistic flow:
//! - `RuntimeConfig::auto()` — auto thread/core sizing from the host CPU
//! - `parallel_map` — bounded fan-out with AggregateError
//! - `RetryExt` — ergonomic `.retry()` on a Future
//! - `ShutdownGuard` — RAII cleanup guaranteed even on panic
//! - `AutoReconnectPool` — self-healing resource pool
//! - `AutoMetricsServiceBuilder` — service calls that auto-record metrics
use std::sync::atomic::{AtomicU32, Ordering};
use std::sync::Arc;
use std::time::Duration;
use mytheclipse::{
aggregate_error::AggregateError,
auto_metrics_service::AutoMetricsServiceBuilder,
parallel_map::parallel_map,
pool::{AutoReconnectPool, Pool, Reconnectable, SemaphorePool},
retry_ext::RetryExt,
runtime_auto::RuntimeConfig,
shutdown_guard::ShutdownGuard,
service_builder::ServiceConfig,
};
#[tokio::main]
async fn main() {
println!("== mytheclipse high-level abstractions demo ==");
// 1. Auto thread/core allocation from host CPU topology.
let cfg = RuntimeConfig::auto();
println!(
"1. RuntimeConfig::auto() -> worker={}, blocking={}, compute={}, io={}",
cfg.worker_threads, cfg.max_blocking_threads, cfg.compute_threads, cfg.io_threads
);
// 2. Bounded parallel fan-out with automatic error aggregation.
let results: Result<Vec<i32>, AggregateError> =
parallel_map(vec![1, 2, 3, 4, 5], 2, |x| async move {
tokio::time::sleep(Duration::from_millis(10)).await;
Ok::<_, std::io::Error>(x * 10)
})
.await;
println!("2. parallel_map -> {:?}", results.unwrap());
// 3. Ergonomic retry on a Future.
let attempts = Arc::new(AtomicU32::new(0));
let a = Arc::clone(&attempts);
let cfg = mytheclipse::retry::RetryConfig {
max_attempts: 4,
base_delay: Duration::from_millis(1),
..Default::default()
};
let fut = async { Err::<u32, String>("boom".into()) };
let op = move || {
let a = Arc::clone(&a);
async move {
let n = a.fetch_add(1, Ordering::SeqCst);
if n < 3 {
Err::<u32, String>("transient".into())
} else {
Ok(42u32)
}
}
};
let value = fut.retry(cfg, |_: &String| true, op).await.unwrap();
println!("3. RetryExt with {} attempts -> {value}", attempts.load(Ordering::SeqCst));
// 4. RAII ShutdownGuard — callback runs exactly once on drop, panic-safe.
let fired = Arc::new(AtomicU32::new(0));
let f = Arc::clone(&fired);
{
let _guard = ShutdownGuard::new(move || {
f.fetch_add(1, Ordering::SeqCst);
});
} // guard dropped -> callback fires
println!(
"4. ShutdownGuard fired {}x (exactly-once, even on unwind)",
fired.load(Ordering::SeqCst)
);
// 5. AutoReconnectPool — transparently replaces dead resources.
let auto = AutoReconnectPool::new(SemaphorePool::new(vec![1u32, 2u32]), Probe { dead: 1 });
let first = auto.acquire().await.unwrap().resource;
// Never the dead value (1) once the probe rejects it.
println!("5. AutoReconnectPool first acquire -> {first}");
// 6. AutoMetricsServiceBuilder — auto records latency + outcome counters.
let mut svc_cfg = ServiceConfig::default();
svc_cfg.max_attempts = 2;
let svc = AutoMetricsServiceBuilder::new("demo_op", svc_cfg);
let n = Arc::new(AtomicU32::new(0));
let n2 = Arc::clone(&n);
let _: Result<u32, mytheclipse::service_builder::RunError<()>> = svc.run(|| {
let n2 = Arc::clone(&n2);
Box::pin(async move {
tokio::time::sleep(Duration::from_millis(5)).await;
let v = n2.fetch_add(1, Ordering::SeqCst);
if v < 1 {
Err(())
} else {
Ok(7u32)
}
})
}).await;
let snap = svc.collector().snapshot();
println!(
"6. AutoMetrics -> {} counters, {} histograms",
snap.counters.len(),
snap.histograms.len()
);
println!("== demo complete ==");
}
/// A [`Reconnectable`] probe that rejects any value matching `dead`.
struct Probe {
dead: u32,
}
#[async_trait::async_trait]
impl Reconnectable for Probe {
type Item = u32;
fn is_healthy(&self, item: &Self::Item) -> bool {
*item != self.dead
}
async fn reconnect(&self) -> Result<Self::Item, Box<dyn std::error::Error + Send + Sync>> {
Ok(999)
}
}