RaftNode

interface RaftNode

The runtime interface for a single Raft cluster member.

Obtain an instance via CoroutineScope.raftNode. The node starts running immediately and remains active until close is called or the owning CoroutineScope is cancelled.

Testing multi-node clusters? Use MultiNodeRaftSim from :kuilt-raft-test — it handles the ceremony (in-process network, per-node seeded RaftConfig.random for symmetry-breaking, child scopes on backgroundScope, bounded await helpers) so you don't hand-roll it per test.

Properties

Link copied to clipboard
abstract val commitIndex: StateFlow<Long>

The index of the highest log entry known to be committed by a quorum.

Link copied to clipboard
abstract val committed: Flow<Committed>

A hot Flow of committed instructions in index order, delivered as Committed values.

Link copied to clipboard
abstract val compactionFloor: StateFlow<Long>

The lastIncludedIndex of the most recent compaction, or 0 if nothing has been compacted.

Link copied to clipboard
abstract val leader: StateFlow<NodeId?>

The NodeId of the node this node currently believes to be the leader, or null if no leader is known (e.g. during an election).

Link copied to clipboard
abstract val membership: StateFlow<ClusterConfig>

The effective cluster membership this node is currently operating under: the ClusterConfig of the latest config entry in its log, committed or not.

Link copied to clipboard
abstract val role: StateFlow<RaftRole>
Link copied to clipboard
abstract val snapshots: MutableStateFlow<Snapshot?>

The outbound snapshot channel. The consumer publishes its latest durable state-machine snapshot here on its own clock (snapshots.value = Snapshot(appliedIndex, bytes)); raft samples it on its own clock to compact the log prefix and to serve a lagging follower. Conflated — only the newest snapshot matters. Leaving it null disables compaction (the pre-compaction behavior).

Link copied to clipboard
abstract val trace: Flow<RaftTraceEvent>

Hot Flow of RaftTraceEvents — one event per engine state transition.

Functions

Link copied to clipboard
open suspend fun awaitLeadership()

Suspends until this node is observed in the RaftRole.Leader role.

Link copied to clipboard
suspend fun RaftNode.awaitRead(applied: StateFlow<Long>): Long

Linearizable read barrier: confirms the read index via RaftNode.readIndex, then suspends until applied reaches it, returning that index. applied is the caller's own monotonic applied-index flow, advanced as it consumes RaftNode.committed.

Link copied to clipboard
open fun cancelTransfer()

Aborts an in-flight transferLeadership and re-enables proposal acceptance.

Link copied to clipboard
open suspend fun changeMembership(target: ClusterConfig): ClusterConfig

Requests a cluster membership change to target, suspending until the change commits as C_new, then returning target.

Link copied to clipboard
suspend fun RaftNode.changeMembershipWithRetry(newConfig: ClusterConfig, maxAttempts: Int = 20, retryDelay: Duration = 200.milliseconds)

Applies a membership change to this node, retrying while a prior change is still settling.

Link copied to clipboard
abstract suspend fun close()

Shuts down this node: stops the actor command loop, cancels the leader's election/heartbeat/ quorum-check/lease timer coroutines, and fails every in-flight or still-buffered request (propose/readIndex/changeMembership/transferLeadership and the internal commit-cut) so no caller's await() hangs.

Link copied to clipboard
abstract fun committedFrom(fromIndex: Long): Flow<Committed>

A cold Flow that replays already-committed Committed values from fromIndex (inclusive), then transparently tails the live committed stream — with no gap or duplicate at the seam.

Link copied to clipboard
abstract suspend fun propose(command: ByteArray): LogEntry

Proposes command for replication and suspends until a quorum commits it.

abstract suspend fun propose(command: ByteArray, requestId: Long): LogEntry

Proposes command with a caller-pinned requestId (Raft §8 client serial) under this node's clientId, then suspends until a quorum commits it (same semantics as propose).

Link copied to clipboard
open suspend fun readIndex(): Long

Confirms this leader still holds a voter-quorum at its current term, then returns a read index: a commit index ri such that any state machine that has applied through ri reflects every write committed before this call. The read is linearizable once the caller's apply loop reaches ri. The leader does not write to the log.

Link copied to clipboard
open suspend fun transferLeadership(target: NodeId)

Initiates a graceful leadership transfer to target per Raft §3.10, and suspends until the transfer is confirmed or fails. It returns normally only when this node observes a leader-authored message from target — an AppendEntries/InstallSnapshot sent by target at a term above the transfer's start term — proof the target actually won an election. An intervening step-down does not resolve the call (the sender of the first higher-term message identifies neither the winner nor even a campaigner): the transfer stays pending until the confirmation arrives or the one-election-timeout auto-abandon fires. Failure still means only that the transfer could not be confirmed within the window: on a degraded/partitioned network the target may have won without its first leader message reaching this node in time.