Deterministic Raft consensus simulator that models leader election, log replication, crash recovery, and lossy networks. It runs entirely on the command line (no external services) and is built to showcase distributed systems fundamentals with clean, modular code.
https://github.com/mohosy/raft-consensus-simulator
- Implements the full Raft control loop: randomized elections, heartbeats, majority-based commits, and log backtracking.
- Fault-injection hooks: crash/restore nodes, isolate replicas, and tune latency/drop rates to observe safety and liveness.
- Deterministic mode via a seeded RNG for reproducible runs—great for teaching and testing.
- Tests prove leader election, log replication, and failover correctness.
- Clear separation of concerns (core protocol, network model, cluster orchestrator, CLI demo).
npm install
npm test # runs deterministic protocol tests
npm start # runs the demo scenario (120 ticks with a leader crash + recovery)
# or
npm run demo # aliasThe built-in scenario spins up 5 nodes, applies client commands, crashes the leader at tick 45, restores it at tick 70, and prints the cluster timeline.
[fault] Crashed leader N1 at tick 45
[recovery] Restored N1 at tick 70
[t=52] leadership-change: N3 became leader for term 4
[t=80] log-commit: N3 applied #6 (term 4) cmd=append log
...
Final replicated state (applied commands per node):
┌─────────┬─────┬─────────────────────────────────────────┬──────┬─────────────┐
│ (index) │ id │ applied │ term │ commitIndex │
├─────────┼─────┼─────────────────────────────────────────┼──────┼─────────────┤
│ 0 │ N1 │ set x=1, set y=2, increment y, set z=9, │ 4 │ 6 │
│ 1 │ N2 │ set x=1, set y=2, increment y, set z=9, │ 4 │ 6 │
│ ... │ ... │ ... │ ... │ ... │
└─────────┴─────┴─────────────────────────────────────────┴──────┴─────────────┘
src/core/raftNode.ts– Raft state machine (Follower/Candidate/Leader), log replication, election timers, commit pipeline.src/simulation/network.ts– Simulated unreliable network with latency, drops, and node isolation.src/simulation/cluster.ts– Orchestrates nodes + message delivery per tick; exposes helpers for fault injection and inspecting state.src/demo/clusterDemo.ts– Deterministic walkthrough used bynpm start.tests/run.ts– Deterministic assertions for election, replication, and failover.
- Time/space: AppendEntries processing is O(k) for k entries in the batch; leader commit calculation is O(N log N) in the worst case (sorting match indices) where N is cluster size.
- Safety: Nodes never apply entries before a majority acknowledgement and only commit entries from the current leader term to avoid the classic Raft safety violation.
- Liveness: Randomized election timeouts avoid split votes; heartbeats prevent unnecessary elections.
- Determinism:
makeDeterministicRandom(seed)gives repeatable simulations for tests and documentation.
- Tweak election/heartbeat timing in
ClusterOptions(seesrc/simulation/cluster.ts). - Simulate partitions:
cluster.isolateNode('N3')thencluster.restoreNetwork('N3'). - Crash/restore nodes:
cluster.setNodeDown('N1')/cluster.restoreNode('N1'). - Feed your own workload by passing commands into
cluster.tick(["cmd"])inside a custom driver.
/raft-consensus-simulator
├── src
│ ├── core
│ │ └── raftNode.ts
│ ├── simulation
│ │ ├── cluster.ts
│ │ └── network.ts
│ ├── demo
│ │ └── clusterDemo.ts
│ └── index.ts
├── tests
│ └── run.ts
└── tsconfig.json
Mo Shirmohammadi • GitHub @mohosy