builds / raft / stage-1SHEET 1 / 6 · REV ASIGN IN
ASSEMBLY DIAGRAM — YOUR RAFT CLUSTERSCALE: LEARNING
clientthe outside worldTIMING CRYSTAL⚙ buildingELECTION CIRCUITstage 2REPLICATION BELTstage 3COMMIT INTERLOCKstage 4BLACK BOXstage 5STORM ENCLOSUREstage 6
BUILTUNDER CONSTRUCTIONNOT YET IMAGINED INTO EXISTENCE
STAGE 1 · THE TIMING CRYSTAL

The Chassis and the Clock

Before a cluster can agree on anything, each node needs a state dial and a clock that notices silence.

What you're wiring up

A Raft node is a small state machine with three modes: follower, candidate, leader. Time is carved into numbered terms, a logical clock that only counts up. Terms are how a node tells fresh news from stale news, and the rule is absolute: see a term higher than yours, adopt it and drop to follower.

The other half of the chassis is the countdown. Every node runs an election timer, and hearing from a live leader resets it. The load-bearing trick is that this timeout is randomized. If all nodes counted down identically they would wake together, campaign together, split the vote, and repeat forever. Randomness is what makes the whole algorithm terminate.

This sheet holds no elections at all. You build the skeleton: the node struct, the state transitions collected in one place, and a clock that fires when the room goes quiet.

# every RPC and every reply carries a term
AppendEntries{term: 5, leaderId: 2}  →  node A
A: currentTerm 0 → 5, state = follower

# a stale message arrives later
AppendEntries{term: 3}  →  A
A replies {term: 5, success: false}

Assembly steps

[ 01 ]
Define the Raft struct in raft/raft.go: currentTerm, votedFor, state, one mutex, and the peer list the harness transport hands you.
hint

One big mutex around all state is the correct starting point. Fine-grained locking is how Raft implementations die young.

hint

Keep the fields private and read them only under the lock; the harness probes state through an accessor that takes the same lock.

[ 02 ]
Implement the state dial: becomeFollower(term), becomeCandidate(), becomeLeader() — each setting state and term consistently in exactly one place.
hint

Every RPC handler and every reply handler will need to step down on a higher term. Centralize it now and you write that rule once instead of six times.

[ 03 ]
Build the election clock: a background goroutine that fires after a randomized timeout in the 150 to 300ms range unless something resets it.
hint

Don't sleep the exact duration. Wake often and compare against a lastHeard timestamp — resets become trivial and the harness's fake clock stays happy.

hint

Draw a fresh random timeout every cycle. Reusing one value per node re-creates the split vote you're trying to avoid.

[ 04 ]
Wire the RequestVote and AppendEntries stubs to do term rules only: reject lower terms, step down on higher ones, reset the clock on a valid leader's AppendEntries.
hint

Put your currentTerm in every reply. That is how a stale caller learns it is stale.

Go deeper (after it passes)

Sheet 1 is a locking-discipline exercise as much as a Raft one — it pairs with the concurrency module's mutex patterns and with Clean Code's case for one-place state transitions. Keep Figure 2 of the extended Raft paper open; you will be re-reading it for the next five sheets.