xiaohongshu
xiaohongshu
Test distributed systems with reproducible deterministic simulation using turmoil
Full skill instructions
Read this when testing distributed systems that need:
Key insight: Control all non-determinism (time, randomness, network, I/O) with a seed = identical behavior every run.
| Pillar | Problem | Solution |
|---|---|---|
| Execution | Thread scheduling is non-deterministic | Single-threaded async executor |
| Entropy | RNGs use system entropy | Seeded PRNG throughout |
| Time | Real clocks advance unpredictably | Simulated clock, manual advancement |
| I/O | Network has variable latency/loss | In-memory simulated network |
| Library | Purpose | Use When |
|---|---|---|
| turmoil | Network simulation for Tokio | Standard TCP/UDP patterns |
| madsim | Full libc interception | Need to catch all entropy/time sources |
| proptest | Property-based input generation | Generating test scenarios |
[features]
default = []
simulation = ["turmoil"]
[dependencies]
tokio = { version = "1", features = ["full"] }
rand = "0.8"
[dev-dependencies]
turmoil = "0.6"
use turmoil::Builder;
use std::time::Duration;
#[test]
fn test_echo_server() {
let mut sim = Builder::new()
.simulation_duration(Duration::from_secs(60))
.build();
// Server
sim.host("server", || async {
let listener = turmoil::net::TcpListener::bind("0.0.0.0:8080").await?;
let (mut socket, _) = listener.accept().await?;
let mut buf = [0u8; 1024];
loop {
let n = socket.read(&mut buf).await?;
if n == 0 { break; }
socket.write_all(&buf[..n]).await?;
}
Ok(())
});
// Client
sim.client("client", async {
let mut socket = turmoil::net::TcpStream::connect("server:8080").await?;
socket.write_all(b"hello").await?;
let mut buf = [0u8; 1024];
let n = socket.read(&mut buf).await?;
assert_eq!(&buf[..n], b"hello");
Ok(())
});
sim.run().unwrap();
}
fn run_with_seed<F>(test_fn: F)
where
F: FnOnce(u64) + std::panic::UnwindSafe
{
let seed: u64 = std::env::var("TEST_SEED")
.ok()
.and_then(|s| s.parse().ok())
.unwrap_or_else(|| rand::random());
println!("TEST_SEED={}", seed);
let result = std::panic::catch_unwind(|| test_fn(seed));
if result.is_err() {
eprintln!("Reproduce with: TEST_SEED={} cargo test", seed);
std::panic::resume_unwind(result.unwrap_err());
}
}
use std::collections::HashMap;
use std::hash::{BuildHasher, Hasher};
#[derive(Clone, Default)]
pub struct DeterministicHasher {
state: u64,
}
impl Hasher for DeterministicHasher {
fn finish(&self) -> u64 {
self.state
}
fn write(&mut self, bytes: &[u8]) {
const FNV_PRIME: u64 = 1099511628211;
for &byte in bytes {
self.state ^= byte as u64;
self.state = self.state.wrapping_mul(FNV_PRIME);
}
}
}
#[derive(Clone, Default)]
pub struct DeterministicBuildHasher;
impl BuildHasher for DeterministicBuildHasher {
type Hasher = DeterministicHasher;
fn build_hasher(&self) -> Self::Hasher {
DeterministicHasher { state: 14695981039346656037 }
}
}
type DetHashMap<K, V> = HashMap<K, V, DeterministicBuildHasher>;
#[tokio::test(flavor = "current_thread", start_paused = true)]
async fn test_timeout() {
let start = tokio::time::Instant::now();
// This doesn't actually wait - time is simulated
tokio::time::sleep(Duration::from_secs(3600)).await;
// But an hour has "passed"
assert_eq!(start.elapsed(), Duration::from_secs(3600));
}
#[cfg(not(feature = "simulation"))]
pub use tokio::net::{TcpListener, TcpStream};
#[cfg(feature = "simulation")]
pub use turmoil::net::{TcpListener, TcpStream};
let mut sim = Builder::new()
.min_message_latency(Duration::from_millis(100))
.max_message_latency(Duration::from_millis(500))
.build();
// Network partition
sim.partition("node-a", "node-b");
// Run during partition
sim.run_until(Duration::from_secs(30));
// Heal partition
sim.repair("node-a", "node-b");
sim.run().unwrap();
// BAD ❌ - Bypasses simulated time
std::time::Instant::now()
std::thread::sleep(duration)
// GOOD ✅ - Uses simulated time
tokio::time::Instant::now()
tokio::time::sleep(duration).await
// BAD ❌ - Order is non-deterministic
for (k, v) in hashmap.iter() {
process_in_order(k, v); // Order affects result!
}
// GOOD ✅ - Use BTreeMap or sort first
let mut items: Vec<_> = hashmap.iter().collect();
items.sort_by_key(|(k, _)| *k);
// BAD ❌ - uuid uses system entropy
let id = uuid::Uuid::new_v4();
// GOOD ✅ - Generate from seeded RNG
let id = uuid::Uuid::from_u128(rng.gen());
#[test]
fn test_survives_partition() {
let seed = 42u64;
let mut rng = StdRng::seed_from_u64(seed);
let mut sim = Builder::new()
.simulation_duration(Duration::from_secs(120))
.build();
// Create 3-node cluster
for i in 0..3 {
let node_name = format!("node-{}", i);
sim.host(&node_name, || async move {
// Consensus participant logic
Ok(())
});
}
// Run normally
sim.run_until(Duration::from_secs(10));
// Random partition
let victim = rng.gen_range(0..3);
sim.partition(
&format!("node-{}", victim),
&format!("node-{}", (victim + 1) % 3)
);
// Run during partition
sim.run_until(Duration::from_secs(30));
// Heal
sim.repair(
&format!("node-{}", victim),
&format!("node-{}", (victim + 1) % 3)
);
// Verify recovery
sim.run().unwrap();
}
#[test]
fn verify_determinism() {
let seed = 12345u64;
let result1 = run_and_capture(seed);
let result2 = run_and_capture(seed);
assert_eq!(result1, result2,
"Non-determinism detected! Check for unseeded RNG or real time.");
}
fn run_and_capture(seed: u64) -> Vec<Event> {
// Run simulation, capture events
// Return events for comparison
}
# With random seed
cargo test --features simulation
# With specific seed for reproduction
TEST_SEED=12345 cargo test --features simulation
# Run specific test
TEST_SEED=42 cargo test test_survives_partition --features simulation
See examples/ directory for working code:
basic-dst-setup.md - Working DST test setup guidebasic-dst-setup.rs - Complete DST test example codeSee docs/ directory for comprehensive guides:
dst-rust-guide.md - Complete DST concepts and turmoil/madsim usagedst-internals-guide.md - Deep dive into DST implementation detailsREADME.md - DST documentation overviewLast Updated: 2026-01-28 Version: 2.1-approved
xiaohongshu
technical spec
product ux expert
database patterns
Conduct multi-agent task orchestration and workflow coordination.
Initialize project with Conductor artifacts (product definition,
Expert in web animations, transitions, and motion design using Framer Motion and CSS
Creates Mermaid and ASCII diagrams for flowcharts, architecture, ERDs, state machines, mindmaps, and more. Use when user mentions diagram, flowchart, mermaid, ASCII diagram, text diagram, terminal diagram, visualize, C4, mindmap, architecture diagram, sequence diagram, ERD, or needs visual docume...
PostgreSQL bindings for H3 hexagonal grid system. Use when working with H3 cells in Postgres, including spatial indexing, geometry/geography integration, and raster analysis.
Context-Driven Development skill for projects using Conductor. Use this skill when you detect a `conductor/` directory in the project, when working on tasks defined in a `plan.md` file, or when the user asks about tracks, specs, or plans. Automatically applies TDD workflow, tracks task completion...
Display project status, active tracks, and next actions
Official Stakpak application containerization standard operating procedure, a step-by-step guidline to properly dockerize applications. This is a rule book curated by the Stakpak Team.
Generate, edit, and beat-sync AI video with leading models in one workspace.
The world's fastest calendar for remote work
Transform Your Design with AI Designer by ImgCreator.ai
Revolutionizing Video Production with AI-Powered Creativity
Extend an image past the frame and let AI fill the new aspect ratio.
Discover your celebrity doppelgänger with StarByFace!
ChainClarity explains 700+ crypto whitepapers in plain English, with layered summaries, comparisons, research tools, alerts, and a $4.99 Pro plan.
Opus.ai: Revolutionize Your Web Experience