~/raft-moonbit

Quickstart

From zero to committed
in four commands

Every command and every line of output on this page is copied from the tested example. The run is deterministic - the same seed always prints the same transcript.

  1. 01

    Add the package

    It lives on mooncakes.io under Lfan-ke; the GitLink repo heke1228/raft-moonbit is the same history.

    # in your MoonBit project
    moon add Lfan-ke/raft-moonbit
  2. 02

    Run the worked example

    Clone the repo and run the bundled five-node scenario: it elects a leader, replicates a command, crashes the leader, and re-elects - printing the safety invariants at each step.

    git clone https://github.com/Lfan-ke/raft-moonbit && cd raft-moonbit
    moon run cmd/example

    Output - verbatim

    cluster of 5 nodes, seed 1
    elected leader: b
    committed 'set x = 1' on a majority
    crashed the leader
    new leader: c
    one leader per term : true
    committed prefixes agree : true
    safety invariants hold : true
  3. 03

    Drive a cluster yourself

    The Cluster simulator is the batteries-included path: build it, elect, propose, and assert the guarantees hold through a fault.

    // Drive a five-node cluster through the deterministic simulator.
    let cluster = @raft.Cluster::new(["a", "b", "c", "d", "e"], seed=1)
    let leader = cluster.run_until_leader(200)          // elect a leader
    let _ = cluster.propose(b"set x = 1")               // replicate a command
    let _ = cluster.run_until_committed(2, 200)         // wait for commit
    
    // Inject a fault and watch the cluster keep its safety guarantees.
    cluster.crash(leader.unwrap())
    let _ = cluster.run_until_leader(400)               // a new leader takes over
    assert_true(cluster.one_leader_per_term())
    assert_true(cluster.committed_agrees())
  4. 04

    Or talk the protocol directly

    For a real transport, drive a RaftNode through the RawNode Ready/Advance loop - take a Ready, persist its entries, send its messages, apply its committed entries, then advance.

    let raw = @raft.RaftNode::new("n1", []).raw()
    raw.campaign()                       // stand for election
    while raw.has_ready() {
      let rd = raw.ready()
      // persist rd.entries, send rd.messages,
      // apply rd.committed_entries to your state machine …
      raw.advance(rd)
    }

Local

Run the browser demo locally

The interactive demo builds from the same consensus core. Compile to WebAssembly, drop the artifact next to the page, and serve docs/ over http - an ES-module / fetch of .wasm needs http(s), not file://.

moon build --target wasm --release
cp _build/wasm/release/build/demo/demo.wasm docs/raft-moonbit.wasm
python3 -m http.server 8099 --directory docs   # open http://localhost:8099/demo.html