feat(cluster): CLUSTER FAILOVER state machine - #188
Merged
Conversation
adds CLUSTER FAILOVER [FORCE|TAKEOVER] to promote a replica to primary.
topology.rs: new ClusterState::promote_replica(replica_id) method
- transfers all slots from the old primary to the promoted node
- demotes the old primary to replica status (replicates the new primary)
- updates replica lists on both nodes
- bumps the global config epoch for conflict resolution
cluster.rs: ClusterCoordinator::cluster_failover(force, takeover)
- default: waits 500ms for replication to catch up, then proposes
PromoteReplica + slot transfer via Raft for cluster-wide agreement
- force: same as default but skips the grace period
- takeover: bypasses Raft entirely; updates local state and announces
the new role via gossip (for when Raft quorum is unavailable)
- adds writes_paused AtomicBool + pause_writes/resume_writes for
future primary-side coordination during default failover
connection.rs:
- replaces the FAILOVER stub with a call to cluster_failover
- adds is_writes_paused check to the write rejection gate
kacy
added a commit
that referenced
this pull request
Feb 19, 2026
adds CLUSTER FAILOVER [FORCE|TAKEOVER] to promote a replica to primary.
topology.rs: new ClusterState::promote_replica(replica_id) method
- transfers all slots from the old primary to the promoted node
- demotes the old primary to replica status (replicates the new primary)
- updates replica lists on both nodes
- bumps the global config epoch for conflict resolution
cluster.rs: ClusterCoordinator::cluster_failover(force, takeover)
- default: waits 500ms for replication to catch up, then proposes
PromoteReplica + slot transfer via Raft for cluster-wide agreement
- force: same as default but skips the grace period
- takeover: bypasses Raft entirely; updates local state and announces
the new role via gossip (for when Raft quorum is unavailable)
- adds writes_paused AtomicBool + pause_writes/resume_writes for
future primary-side coordination during default failover
connection.rs:
- replaces the FAILOVER stub with a call to cluster_failover
- adds is_writes_paused check to the write rejection gate
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
summary
implements
CLUSTER FAILOVER [FORCE|TAKEOVER]— the manual failover command that promotes a replica to primary.three modes:
PromoteReplica+ slot transfer via Raft for cluster-wide agreement. safe for planned maintenance failovers.topology.rs — new
ClusterState::promote_replica(replica_id):NodeRole::Replica(pointing back at the new primary)slotscacheconfig_epochfor conflict resolutioncluster.rs —
ClusterCoordinator::cluster_failover(force, takeover):ClusterCommand::PromoteReplica+AssignSlots+RemoveSlotsvia Raftwrites_paused: AtomicBoolwithpause_writes/resume_writesfor future primary-side coordination during default failoverconnection.rs:
cluster.cluster_failover(force, takeover)is_writes_paused()so a primary can be paused during coordinated failoverwhat was tested
cargo test --workspace: 86 cluster unit tests, 68 server unit tests — all passcargo clippy --workspace -- -D warnings: cleanpromote_replica_transfers_slots,promote_replica_rejects_non_replica,promote_replica_rejects_unknown_node(topology),failover_rejected_on_primary,failover_takeover_promotes_replica,writes_paused_blocks_and_resumes(cluster coordinator)design considerations
the 500ms grace period in default mode is a heuristic — a proper implementation would track the exact replication offset per shard and wait for the replica to reach the primary's committed offset. that requires the replication client to expose its current offset back to the coordinator, which is a natural follow-up to pr 4 (automatic failover).
pause_writesandresume_writeson the primary side require a coordination channel (the primary needs to receive a pause request from the replica). the infrastructure is now in place; the protocol message is the remaining piece.