# Raft Overview: Roles, Terms and RPCs — Distributed Systems & Consensus (Raft / Paxos)

Source: https://www.skillbyai.com/en/distributed-consensus/dc-raft-overview

> Describe Raft's three roles, the meaning of terms, and the two RPCs that drive the protocol.

## Designed to be understandable

**Raft** (Ongaro and Ousterhout) is a consensus algorithm for managing a replicated log, designed explicitly for understandability. It splits the problem into **leader election**, **log replication** and **safety**. At any moment each server is a **follower** (passive, answers RPCs), a **candidate** (trying to become leader) or the **leader** (handles all client requests and replicates the log). Time is divided into **terms**, numbered with consecutive integers. Each term begins with an election and has at most one leader. Terms act as a **logical clock**: every RPC carries the sender's term; a server that sees a higher term updates its own and becomes a follower, and a request with a stale term is rejected. Only two RPCs are needed for the core protocol: **RequestVote**, sent by candidates, and **AppendEntries**, sent by the leader both to replicate entries and, when empty, as a **heartbeat**. Each server persists `currentTerm`, `votedFor` and its log before answering.

## Raft server roles

A follower that hears no heartbeat becomes a candidate; a candidate that wins a majority becomes leader; any server that sees a higher term returns to follower.

![Three stages in a cycle: follower, candidate, and leader.](assets/figures/distributed-consensus/section-6-map.svg) — Figure 6.1: follower -> candidate (election timeout) -> leader (majority of votes), and back to follower on a higher term

## The term rule

Every RPC handler starts with the same check. A leader that sees term 7 while it is in term 5 steps down immediately; a message from an older term is rejected.

```python
class Node:
    def __init__(self, name):
        self.name, self.term, self.role = name, 0, "follower"

    def on_message(self, msg_term):
        if msg_term > self.term:          # newer term seen: step down
            self.term, self.role = msg_term, "follower"
            return "updated"
        if msg_term < self.term:          # stale sender: reject
            return "reject (stale term)"
        return "ok"

n = Node("n1")
n.term, n.role = 5, "leader"
print(n.on_message(4), n.role, n.term)
print(n.on_message(7), n.role, n.term)
```

Output:

```
reject (stale term) leader 5
updated follower 7
```

## Persist before you reply

`currentTerm`, `votedFor` and log entries must be on stable storage before a server responds to an RPC. Everything else (commitIndex, lastApplied, nextIndex, matchIndex) is volatile and can be rebuilt after a restart.

**Quiz:** A Raft leader in term 5 receives an AppendEntries response carrying term 8. What does it do?

- [ ] Ignore it, since leaders outrank followers
- [ ] Send a heartbeat to reassert leadership
- [ ] Start a new election in term 6
- [x] Update its term to 8 and become a follower

*Answer:* Update its term to 8 and become a follower. Seeing a higher term means its leadership is stale. It adopts the higher term and reverts to follower.
