diff --git a/.changelog/11376.txt b/.changelog/11376.txt index f3924d102a..d495fd345c 100644 --- a/.changelog/11376.txt +++ b/.changelog/11376.txt @@ -1,3 +1,3 @@ ```release-note:enhancement -try to transfer leadership to another server when leaving. +raft: Consul leaders will attempt to transfer leadership to another server as part of gracefully leaving the cluster. ``` diff --git a/agent/consul/server.go b/agent/consul/server.go index 5996bd435a..65f09d204f 100644 --- a/agent/consul/server.go +++ b/agent/consul/server.go @@ -977,6 +977,22 @@ func (s *Server) Shutdown() error { return nil } +func (s *Server) attemptLeadershipTransfer() (success bool) { + leadershipTransferVersion := version.Must(version.NewVersion(LeaderTransferMinVersion)) + + ok, _ := ServersInDCMeetMinimumVersion(s, s.config.Datacenter, leadershipTransferVersion) + if !ok { + return false + } + + future := s.raft.LeadershipTransfer() + if err := future.Error(); err != nil { + s.logger.Error("failed to transfer leadership, removing the server", "error", err) + return false + } + return true +} + // Leave is used to prepare for a graceful shutdown of the server func (s *Server) Leave() error { s.logger.Info("server starting leave") @@ -996,24 +1012,9 @@ func (s *Server) Leave() error { // removed for some reasonable period of time. isLeader := s.IsLeader() if isLeader && numPeers > 1 { - leadershipTransferVersion := version.Must(version.NewVersion(LeaderTransferMinVersion)) - removeServer := false - if ok, _ := ServersInDCMeetMinimumVersion(s, s.config.Datacenter, leadershipTransferVersion); !ok { - // Transfer leadership to another node then leave the cluster - future := s.raft.LeadershipTransfer() - if err := future.Error(); err != nil { - s.logger.Error("failed to transfer leadership, removing the server", "error", err) - // leadership transfer failed, fallback to removing the server from raft - removeServer = true - } else { - // we are not leader anymore, continue the flow to leave as follower - isLeader = false - } + if s.attemptLeadershipTransfer() { + isLeader = false } else { - // Leadership transfer is not available in the current version, fallback to removing the server from raft - removeServer = true - } - if removeServer { future := s.raft.RemoveServer(raft.ServerID(s.config.NodeID), 0, 0) if err := future.Error(); err != nil { s.logger.Error("failed to remove ourself as raft peer", "error", err)