class

Raft::Node(T)

Inherits Raft::AdminOps < Raft::StatusSource < Reference < Object

Implements the Raft consensus protocol for a single peer in a single group. Generic over T, the application's command type.

Threading contract

A Node is single-fiber. All five public entry points — tick, step, propose, take_messages, and read_index — and all registration methods (on_role_change, on_configuration_change, on_configuration_applied) must be called from the same fiber that owns the node's loop. Internal state (@current_term, @log, @peers, @outbox, @pending_reads, @pending_apply) is mutated without locks because of this invariant.

Callbacks fire on that same fiber and must therefore be non-blocking — channel a signal to your own fiber if you need to do real work.

If you need to call propose from a different fiber (e.g. an HTTP handler), send the request over a channel and have the loop fiber do the actual call. The KV and queue examples demonstrate this pattern in start_group_loop.

Constructors

new(id : NodeID, peers : Array(NodeID), config : Config, state_machine : StateMachine(T), metrics : Metrics | Nil = nil, group_id : UInt64 = 0_u64, address : String = "")
Source

Instance methods

add_server(node_id : NodeID, address : String = "") : Bool

Add a new node to the cluster as a learner, or re-admit a returning member.

  • New id: adds as Learner, returns true.
  • Known id, different non-empty address: updates the stored address and replicates the new configuration, returns true.
  • Known id, same address (or empty address passed): no-op, returns true. Returns false if not leader, if a configuration change is already in flight, or if node_id == @id.
Source
address
Source
bootstrap

Bootstrap this node as a single-node cluster. Only works when the node has no peers (fresh start).

Source
close
Source
commit_index
Source
current_term
Source
first_log_index
Source
group_id
Source
inbox
Source
last_applied
Source
last_log_index

T-free log scalars for StatusSource — let status/metrics consumers read log shape without holding a reference to the mutable Log(T).

Source
last_log_term
Source
leader_id
Source
learners
Source
metrics
Source
on_configuration_applied

Fires whenever the peer list changes — both when config entries are stored in the log (followers, before commit) and when they're committed (leader). Use this to register transport peer addresses from config entries; followers can route to new peers as soon as they see the entry, without waiting for the cluster commit cycle.

Runs on the Raft fiber; keep it non-blocking. See class docs for the full threading contract.

Source
on_configuration_change

Fires when a Configuration entry is committed (apply phase). Block receives the new peer list. Use this for actions that should only run after a membership change is durable across a majority — e.g. cascading data-group reconfiguration in a multi-raft setup.

Runs on the Raft fiber; keep it non-blocking. See class docs for the full threading contract.

Source
on_role_change

Called on every role transition (Follower → Candidate, Candidate → Leader, Leader → Follower, etc.). Block receives (old_role, new_role).

The block runs on the Raft fiber — keep it non-blocking. For work that needs to be done off the Raft fiber (e.g., AMQP listener startup on becoming leader), set a flag or signal a channel from the block and let another fiber do the heavy lifting.

Fires on every transition, including intermediate ones (Follower → Candidate without then becoming Leader). Filter on new_role if you only care about specific transitions.

Source
peers
Source
promote_learner(node_id : NodeID) : Bool

Promote a learner to voter. Returns false if not leader or node is not a learner.

Source
propose(data : T) : Bool
Source
read_index

Linearizable read primitive. Block fires with the commit_index that is safe to read at, or nil if leadership could not be confirmed.

Behaviour:

  • On a non-leader: callback fires synchronously with nil.
  • On a standalone leader (no other voters): registered for the apply gate only; fires once @last_applied >= the captured commit_index.
  • On a multi-voter leader: waits for a heartbeat-ack quorum to confirm leadership at or after registration time, then waits for the apply gate.

The callback fires with nil in three cases: the node is not the leader at call time; the leader steps down before quorum confirmation; or Config.read_index_timeout_ticks ticks elapse without quorum confirmation. Note: once a read is quorum-confirmed and parked at the apply gate, it has no upper time bound — a wedged state machine will hold reads open indefinitely until the node steps down.

Source
remove_server(node_id : NodeID) : Bool

Remove a node from the cluster. Returns false if not leader, node not found, or trying to remove self.

Source
role
Source
segment_count
Source
snapshot_index
Source
snapshot_size_bytes
Source
snapshot_term
Source
step(message : Message)
Source
take_messages
Source
tick
Source
transfer_leadership(to target : NodeID) : Bool
Source
voted_for
Source
voters
Source