Build Raft — consensus you can defend (12 scenes)
Scene 02 · Term — the logical clock
A term is a monotonic int that segments time, with at most one leader per term. The universal step-down rule (any server seeing T' > currentTerm becomes a follower at T') is the simplest mechanism in Raft and underpins everything else.
Previously
You know from scene 01 that safety has to hold even when messages arrive late, out of order, or not at all — and that the wall clock can't be trusted. So before Raft can do anything else, it needs its own notion of time: a counter the whole cluster can agree on without asking a clock. That counter is what this scene builds.
Scene 02
Term — Raft's round counter
Diagram
Three servers (S1, S2, S3) drawn as boxes. Each box shows: (a) what the server thinks its role is — passive listener (the precise word is **follower**), someone running for office (**candidate**), or the one server allowed to make decisions right now (**leader**); (b) the round counter the server currently believes we are on (the precise word for this is **currentTerm**); (c) which server it voted for in this round, if any (**votedFor**); and (d) a small strip of log entries colored by the round that created them. Arrows between boxes are network messages — election asks (RequestVote) and the heartbeats / data shipments leaders send (AppendEntries) — each tagged with the round number it claims to be from. As you drag the slider the role badges and round numbers update together.
currentTerm — each server's own copy of 'what round do I think we're on?' →
S1 is the one leader of round 1; S2 and S3 are followers (just listening) →
You know from scene 01 that the cluster has to agree on a history without trusting the wall clock. The question this scene answers is: what does Raft use instead? Look at the three servers. They all say they are on round 1. One server (S1) is currently in charge — it is allowed to make decisions for round 1 and tell the others what to do. The other two are just listening. Three new words for what you see. First, the round counter itself: think of it like the season number of a TV show — once you start season 4, season 3 is over forever. The precise term is **term** — a monotonically increasing integer, shared by the whole protocol, where at most one server is ever in charge during a single term. Second, each server keeps its own copy of 'what season do I think we are in?' — the precise name for that field is **currentTerm**. Third, the role each server is playing right now: passive listener is called a **follower**, the one in charge is called the **leader**, and (you'll meet this one next phase) a server running for the job is called a **candidate**.
Implementation
Server.onReceiveRPC
universal step-down — runs at the TOP of every RPC handler
1def onReceiveRPC(rpc):2 if rpc.term > currentTerm:3 currentTerm = rpc.term # adopt newer term4 votedFor = None # clear vote for new term5 role = follower # step down6 persist(currentTerm, votedFor) # §5.2 persist barrier7 if rpc.term < currentTerm:8 reply(term=currentTerm, success=False)9 return10 # rpc.term == currentTerm: dispatch to kind-specific logic
Server.state
per-server state — every leader / candidate / follower holds these
1# Persisted (fsync'd before responding to dependent RPCs):2currentTerm : monotonic int # latest term observed3votedFor : ServerId | None # vote granted in currentTerm4log : list[{term, cmd}] # replicated entries, term-tagged56# Volatile on every server:7commitIndex : int = 08lastApplied : int = 0910# Volatile on leader only:11nextIndex : dict[ServerId, int]12matchIndex : dict[ServerId, int]