Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Forbid removed node from being a Candidate #476

Merged
merged 9 commits into from Oct 7, 2021
11 changes: 11 additions & 0 deletions configuration.go
Expand Up @@ -173,6 +173,17 @@ func hasVote(configuration Configuration, id ServerID) bool {
return false
}

// hasVote returns true if the server identified by 'id' is a Voter in the
// provided Configuration.
func inConfig(configuration Configuration, id ServerID) bool {
for _, server := range configuration.Servers {
if server.ID == id {
return true
}
}
return false
}

// checkConfiguration tests a cluster membership configuration for common
// errors.
func checkConfiguration(configuration Configuration) error {
Expand Down
13 changes: 10 additions & 3 deletions raft.go
Expand Up @@ -213,10 +213,17 @@ func (r *Raft) runFollower() {
didWarn = true
}
} else {
r.logger.Warn("heartbeat timeout reached, starting election", "last-leader", lastLeader)
metrics.IncrCounter([]string{"raft", "transition", "heartbeat_timeout"}, 1)
r.setState(Candidate)
return
if inConfig(r.configurations.latest, r.localID) {
r.logger.Warn("heartbeat timeout reached, starting election", "last-leader", lastLeader)
r.setState(Candidate)
return
} else {
if !didWarn {
r.logger.Warn("heartbeat timeout reached, not part of stable configuration, not triggering a leader election")
didWarn = true
}
}
}

case <-r.shutdownCh:
Expand Down
3 changes: 3 additions & 0 deletions raft_test.go
Expand Up @@ -697,6 +697,9 @@ func TestRaft_RemoveFollower(t *testing.T) {
if configuration := c.getConfiguration(followers[1]); len(configuration.Servers) != 2 {
t.Fatalf("too many peers")
}

// The removed node should remain in a follower state
require.Equal(t, Follower, follower.getState())
}

func TestRaft_RemoveLeader(t *testing.T) {
Expand Down