MadSim Documentation

repository·main·Indexed 22 days ago

https://github.com/madsim-rs/madsim

A deterministic async runtime for Rust designed for testing distributed systems. MadSim enables reproducible simulation of chaos, network failures, and randomness. It provides simulator replacements for common crates including tokio, tonic, etcd-client, rdkafka, and aws-sdk-s3, allowing developers to inject failures and amplify randomness to debug complex distributed systems.

Tokens
49.8K
Snippets
146
Records
203
Agent score
76%

What's inside MadSim

  1. What is Deterministic Simulation Testing in MadSim?

    main

    MadSim is an async runtime designed for deterministic simulation testing. Unlike standard runtimes, MadSim can:

    1. Amplify randomness: Control and repeat specific random sequences.
    2. Create chaos: Inject network partitions, disconnect nodes, or kill processes.
    3. Inject failures: Simulate I/O errors and other system uncertainties.

    Because the simulation is deterministic, any bug revealed by the simulator can be reproduced exactly by using the same seed, allowing for reliable debugging of complex distributed systems. To control these behaviors, use the APIs provided by the madsim feature.

  2. How madsim-tonic-build handles code generation for simulation

    main

    Unlike standard tonic-build, madsim-tonic-build generates two sets of code: the original gRPC stubs and specialized code for MadSim simulation.

    Integration is handled via the madsim_tonic::include_proto macro. This macro acts as a feature gate:

    • If the sim feature is enabled: It includes the simulation-compatible versions of the proto definitions.
    • If the sim feature is disabled: It includes the standard gRPC definitions.

    This allows you to use the same source code for both production runs and deterministic simulation tests by simply toggling a feature flag.

  3. Use madsim-tonic for deterministic gRPC simulation

    main

    The madsim-tonic crate provides a simulator for tonic, allowing you to run gRPC services within the MadSim deterministic simulation environment. It is designed to be a drop-in replacement for the standard tonic and tonic-build crates. To use it, you must replace your existing tonic and tonic-build dependencies in Cargo.toml with the madsim versions using the package key to maintain compatibility with your existing code.

    [dependencies]
    tonic = { version = "0.5", package = "madsim-tonic" }
    
    [dev-dependencies]
    tonic-build = { version = "0.5", package = "madsim-tonic-build" }
  4. Use madsim-tonic-build to generate simulation-ready gRPC stubs

    main

    The madsim-tonic-build crate is a drop-in replacement for tonic-build designed for deterministic simulation testing. It compiles .proto files using prost and generates both the original gRPC service stubs and additional code required for MadSim simulation.

    To switch between standard gRPC code and simulation-compatible code, use the madsim_tonic::include_proto! macro. The macro automatically selects the correct version of the generated code based on whether the sim feature is enabled in your project.

    // The macro decides which version to use based on the 'sim' feature
    madsim_tonic::include_proto!("your_package_name");
  5. Use madsim-etcd-client in your project

    main

    To use the madsim-etcd-client simulator, you must replace your existing etcd-client dependency in Cargo.toml with the madsim-etcd-client package. This allows you to use the same API as the original etcd-client while running within the MadSim deterministic simulation environment.

    [dependencies]
    etcd-client = { version = "0.6", package = "madsim-etcd-client" }
  6. Install MadSim

    main

    To use MadSim in your Rust project, add the madsim crate to your Cargo.toml dependencies.

    If your project uses specific distributed system crates like tokio, tonic, etcd-client, rdkafka, or aws-sdk-s3, you should replace them with their corresponding MadSim simulator packages to enable deterministic simulation.

    [dependencies]
    madsim = "0.2"
    
    # Replace standard crates with MadSim simulators
    tokio = { version = "0.2", package = "madsim-tokio" }
    tonic = { version = "0.5", package = "madsim-tonic" }
    etcd-client = { version = "0.4", package = "madsim-etcd-client" }
    rdkafka = { version = "0.3", package = "madsim-rdkafka" }
    aws-sdk-s3 = { version = "0.5", package = "madsim-aws-sdk-s3" }
    
    [dev-dependencies]
    tonic-build = { version = "0.5", package = "madsim-tonic-build" }
  7. Use madsim-tokio as a drop-in replacement for tokio

    main

    The madsim-tokio crate provides a tokio simulator for madsim. It is designed to be a drop-in replacement, meaning if your code looks, acts, and is used like tokio, it should work with madsim-tokio without code changes.

    To use it, you must replace the standard tokio dependency in your Cargo.toml with madsim-tokio using the package key to ensure the crate name remains tokio in your source code.

    [dependencies]
    tokio = { version = "0.2", package = "madsim-tokio" }
  8. Use madsim-rdkafka in your project

    main

    To use the rdkafka simulator within madsim, you must replace your standard rdkafka dependency in Cargo.toml with the madsim-rdkafka package. This allows you to use the same API surface while running under the madsim deterministic simulator.

    Note that while it mirrors rdkafka v0.34.0 and librdkafka 2.3.0, there are specific API modifications regarding async behavior and DNS resolution.

    [dependencies]
    rdkafka = { version = "0.4", package = "madsim-rdkafka" }
  9. Patch dependencies for MadSim compatibility

    main

    Some crates in your dependency graph must be patched to ensure all uncertainties (like randomness or time) are eliminated during simulation. Add the following to your Cargo.toml under the [patch.crates-io] section to use the MadSim-compatible versions of quanta, getrandom, tokio-retry, tokio-postgres, and tokio-stream.

    [patch.crates-io]
    quanta = { git = "https://github.com/madsim-rs/quanta.git", rev = "948bdc3" }
    getrandom = { git = "https://github.com/madsim-rs/getrandom.git", rev = "8daf97e" }
    tokio-retry = { git = "https://github.com/madsim-rs/rust-tokio-retry.git", rev = "95e2fd3" }
    tokio-postgres = { git = "https://github.com/madsim-rs/rust-postgres.git", rev = "4538cd6" }
    tokio-stream = { git = "https://github.com/madsim-rs/tokio.git", rev = "ab251ad" }
  10. Use madsim-aws-sdk-s3 as a replacement for aws-sdk-s3

    main

    The madsim-aws-sdk-s3 crate provides a simulator for the AWS S3 SDK. It mirrors the behavior of aws-sdk-s3 v1.2.0, allowing you to use S3-compatible APIs within a deterministic simulation environment. To use it, you must replace your existing aws-sdk-s3 dependency in Cargo.toml with the madsim-aws-sdk-s3 package.

    [dependencies]
    aws-sdk-s3 = { version = "0.5", package = "madsim-aws-sdk-s3" }
  11. Run tests in the MadSim simulator

    main

    To execute your code within the deterministic simulation environment instead of the standard runtime, you must enable the madsim configuration via RUSTFLAGS when running your tests.

    This replaces standard behaviors (like tokio or tonic) with the simulator's mocked I/O and failure injection logic.

    RUSTFLAGS="--cfg madsim" cargo test
  12. What is the ToSocketAddrs trait?

    main

    The ToSocketAddrs trait is used to convert various address representations (like strings, SocketAddr, or (IpAddr, u16) tuples) into one or more SocketAddr values.

    Key behaviors:

    • DNS Resolution: Implementing ToSocketAddrs for string types (e.g., &str, String) triggers a DNS lookup.
    • Non-blocking: Conversions are designed to be non-blocking within the simulation.
    • Usage: While the trait is sealed and intended to be opaque, it is primarily used as an argument to MadSim functions that require a target socket address. For direct conversion, prefer using lookup_host() instead of calling trait methods directly.