Build Leader Election
Build Leader Election (Raft-style)
The moment you have more than one replica, you need to agree on who's in charge — otherwise two nodes both think they're the primary (split-brain) and corrupt your data. This project builds the election at the heart of Raft: terms, votes, and majority. It's the capstone that ties together the quorum math you visualized and the WAL you built (Raft's log is a replicated WAL). Getting election right — and knowing why the tricky parts exist — is what "I understand consensus" actually means.
The spec
- Terms: a monotonically increasing number; every message carries its term. A higher term always wins (the sender is more current) and forces the receiver to step down to follower.
- Election timeout: a follower that hears no heartbeat from a leader becomes a candidate, bumps the term, and votes for itself.
- RequestVote: a node grants its vote at most once per term (first-come), so a term has at most one leader.
- Majority wins: a candidate with votes from ⌊N/2⌋+1 nodes becomes leader and starts sending heartbeats.
- Randomized timeouts: stagger election timeouts so nodes rarely candidate at once — the fix for repeated split votes.
The two ideas that make it correct
Majority overlap. Any two majorities of N nodes share at least one node (the same pigeonhole as R+W>N in the quorum debugger). So two candidates in the same term can't both collect a majority → at most one leader per term. Term + vote-once. A node votes once per term, and any higher term instantly demotes a stale leader — so a leader that was network-partitioned can't keep acting once the majority has moved on. Together these prevent split-brain.
Reference — election core (Go)
type State int
const ( Follower State = iota; Candidate; Leader )
type Node struct {
mu sync.Mutex
id, n int
term int // currentTerm
votedFor int // -1 = none this term
state State
}
// Triggered when the election timeout fires with no heartbeat.
func (nd *Node) startElection(peers []*Node) {
nd.mu.Lock()
nd.term++; nd.state = Candidate; nd.votedFor = nd.id // vote for self
term, votes := nd.term, 1
nd.mu.Unlock()
for _, p := range peers {
if p.RequestVote(term, nd.id) { votes++ }
}
nd.mu.Lock(); defer nd.mu.Unlock()
if nd.state == Candidate && nd.term == term && votes > nd.n/2 {
nd.state = Leader // majority → leader; now send heartbeats
}
}
// RequestVote receiver: grant at most one vote per term; higher term demotes us.
func (nd *Node) RequestVote(term, candidate int) bool {
nd.mu.Lock(); defer nd.mu.Unlock()
if term < nd.term { return false } // stale candidate
if term > nd.term { nd.term = term; nd.votedFor = -1; nd.state = Follower }
if nd.votedFor == -1 || nd.votedFor == candidate { // first-come, once per term
nd.votedFor = candidate; return true
}
return false
}
// Any RPC (heartbeat/vote) seen with a higher term:
func (nd *Node) observe(term int) {
if term > nd.term { nd.term = term; nd.state = Follower; nd.votedFor = -1 } // step down
}
Reference — vote handler (Java)
synchronized boolean requestVote(int term, int candidateId) {
if (term < this.term) return false; // candidate is behind
if (term > this.term) { this.term = term; this.votedFor = -1; this.state = FOLLOWER; }
if (votedFor == -1 || votedFor == candidateId) { // one vote per term
votedFor = candidateId;
return true;
}
return false;
}
// becomeCandidate(): term++, votedFor=self, votes=1, RequestVote all peers;
// if votes > n/2 && still candidate in this term -> LEADER.
// Election timeout is randomized (e.g. 150–300ms) to avoid split votes.
Tests to write
- Happy election: 5 nodes, one times out first → collects 3 votes → becomes the only leader for that term.
- One leader per term: two candidates in the same term → at most one gets a majority (assert never two leaders in a term). This is the split-brain safety property.
- Higher term wins: an old leader (term 2) receives a message with term 3 → it steps down to follower.
- Split vote → retry: force two candidates to tie; with randomized timeouts, a later term elects a single leader (no permanent deadlock).
Extensions
- Heartbeats + log replication: the leader appends client commands to its WAL and replicates to followers; an entry commits once a majority has it. That's full Raft — the log you already built, agreed by majority.
- Log-freshness in votes: real Raft only grants a vote if the candidate's log is at least as up-to-date, so a leader never loses committed entries.
- Membership changes & lease reads: the hard, interview-worthy corners of consensus.
- Compare: lease-based election (a TTL lock in etcd/ZooKeeper) vs quorum election — when each is appropriate.
What you've mastered
- Why majority overlap + one-vote-per-term guarantees at most one leader per term (no split-brain) — the same pigeonhole as quorum reads.
- How terms demote stale/partitioned leaders, and why election timeouts must be randomized.
- That Raft = this election + a replicated WAL — connecting the two things you built into how real consensus works.
🤖 Don't fully get this? Learn it with Claude
Stuck on Build Leader Election? Open Claude, copy a block below, and it'll teach you this exact concept — visually and interactively.
Build the mental picture, not memorization.
I just read a lesson on **Build Leader Election** (Hands-On Builds) and want to truly understand it. Explain Build Leader Election from first principles using ONE vivid real-world analogy and a visual mental model — draw it as ASCII art or a clear step-by-step diagram — with a concrete example using real numbers. Then ask me one question to check I got the mental picture, and wait for my reply. If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.
Socratic — adapts to where you're stuck.
Teach me **Build Leader Election** interactively. Ask me ONE guiding question at a time, wait for my answer, and adapt to my confusion — build the idea with me step by step instead of explaining it all at once. If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.
Active recall exposes what you missed.
Quiz me on **Build Leader Election** with 5 questions, easy to tricky, ONE at a time. Tell me if each answer is right; at the end, explain clearly what I got wrong and why. If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.
Intuition + hook + flashcards for long-term memory.
Help me remember **Build Leader Election** for the long term: give the one-sentence intuition, a memorable hook/mnemonic, a tiny worked example, and 3 active-recall flashcards (Q -> A). If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.