From c87ae760bfe4b5300ed1418288d984c972b5d561 Mon Sep 17 00:00:00 2001 From: asepharyana Date: Sat, 29 Aug 2026 21:27:07 +0700 Subject: [PATCH] docs: high_level example wiring round-7-15 abstractions --- .hermes/plans/mytheclipse-round16-spec.md | 33 ++++++ crates/mytheclipse/examples/high_level.rs | 134 ++++++++++++++++++++++ 2 files changed, 167 insertions(+) create mode 100644 .hermes/plans/mytheclipse-round16-spec.md create mode 100644 crates/mytheclipse/examples/high_level.rs diff --git a/.hermes/plans/mytheclipse-round16-spec.md b/.hermes/plans/mytheclipse-round16-spec.md new file mode 100644 index 0000000..49af447 --- /dev/null +++ b/.hermes/plans/mytheclipse-round16-spec.md @@ -0,0 +1,33 @@ +# Implementation Spec: Round 16 — COMPLETE + +## Goal +Make the round-7-15 abstractions actually usable — a single, runnable, wired +example showing high-level primitives composing together. + +## New File + +### examples/high_level.rs (mytheclipse-core) +`crates/mytheclipse/examples/high_level.rs` +- One realistic flow demoing, wired together: + 1. RuntimeConfig::auto() — auto thread/core sizing from host CPU + 2. parallel_map — bounded fan-out + AggregateError + 3. RetryExt — ergonomic .retry() on a Future + 4. ShutdownGuard — RAII exactly-once cleanup + 5. AutoReconnectPool — self-healing resource pool (dead value replaced) + 6. AutoMetricsServiceBuilder — auto latency/outcome metrics +- Run: `cargo run -p mytheclipse --features full --example high_level` + +## Verified Output (real run, 8-core host) +``` +1. RuntimeConfig::auto() -> worker=8, blocking=12, compute=8, io=4 +2. parallel_map -> [10, 20, 30, 40, 50] +3. RetryExt with 4 attempts -> 42 +4. ShutdownGuard fired 1x (exactly-once, even on unwind) +5. AutoReconnectPool first acquire -> 999 +6. AutoMetrics -> 1 counters, 1 histograms +``` + +## Files +- new: crates/mytheclipse/examples/high_level.rs + +Build: exit 0. Run: succeeds (verified above). diff --git a/crates/mytheclipse/examples/high_level.rs b/crates/mytheclipse/examples/high_level.rs new file mode 100644 index 0000000..0d9a4c8 --- /dev/null +++ b/crates/mytheclipse/examples/high_level.rs @@ -0,0 +1,134 @@ +//! 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, 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::("boom".into()) }; + let op = move || { + let a = Arc::clone(&a); + async move { + let n = a.fetch_add(1, Ordering::SeqCst); + if n < 3 { + Err::("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> = 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> { + Ok(999) + } +}