sumanpal97 opened a new pull request, #23168:
URL: https://github.com/apache/kafka/pull/23168

   On a clean shutdown the leader sends `EndQuorumEpoch` carrying a list of 
preferred successors ordered by log end offset, and each successor waits a 
backoff proportional to its position before standing for election. The first 
entry, being the most up to date, is expected to win.
   
   It cannot. `FollowerState.canGrantVote()` rejects a pre-vote whenever 
`hasFetchedFromLeader` is true, without accounting for the leader having 
already announced that it is resigning. With more than three voters the first 
successor collects only its own vote and the resigned leader's, which is not a 
majority, so it loses and returns to follower. The second entry then wins, 
because by that point the first entry has transitioned away from follower and 
is able to vote. The pattern repeats for larger quorums: the third entry wins 
with six or seven voters, the fourth with eight or nine. Every graceful 
controller shutdown therefore wastes an election round, which is the degraded 
availability described in the JIRA.
   
   This change tracks whether the leader of the current epoch has resigned, and 
lets a follower grant a pre-vote in that case even if it has already fetched, 
as long as the requester's log is up to date. Granting is no longer disruptive 
once the leader has stepped down, so the disruptive-candidate protection 
introduced by KIP-996 is not weakened for a healthy leader. Standard votes are 
unaffected, since the new condition sits behind the existing `isPreVote` guard.
   
   The flag lives on `FollowerState` and needs no explicit reset: `QuorumState` 
allocates a fresh `FollowerState` on every transition, so it is naturally 
scoped to one epoch and leader, exactly like the existing 
`hasFetchedFromLeader`. It is set in `handleEndQuorumEpochRequest` only when 
the replica is still a follower and the request came from its own leader.
   
   ### Testing strategy
   
   
`RaftEventSimulationTest.preferredSuccessorWinsElectionAfterGracefulLeaderShutdown`
 is a multi-node simulation that starts a quorum, waits for a leader and for 
every replica to converge on the same log so the resigning leader is able to 
grant pre-votes, reads the ranking the leader will advertise via 
`LeaderState.nonLeaderVotersByDescendingFetchOffset()`, shuts the leader down 
gracefully, and asserts that the first entry of that advertised ranking becomes 
the new leader. The ranking is read from the leader rather than hardcoded, so 
the assertion does not depend on which node happens to be elected first.
   
   It is parameterized over four through nine voters. Without the production 
change it fails for all six sizes, and the winner lands at exactly the position 
the JIRA predicts: the second entry for four and five voters, the third for six 
and seven, the fourth for eight and nine. With the change all six elect the 
first entry, and the election completes in roughly 30 ms instead of waiting out 
a backoff.
   
   Nine voters is the upper bound because `strictExponentialElectionBackoffMs` 
right-shifts the configured maximum by the number of successors, so beyond that 
the base backoff falls below the simulation's polling interval and the 
successors no longer stand for election one at a time. The test also raises 
`election.backoff.max.ms` to the production default via a new mutable field on 
the simulation's `Cluster`; the other simulations lower it to keep their 
runtime down, but here the gap between successive candidates is the behavior 
under test.
   
   An `@ParameterizedTest` was used rather than the class's 
`withVotersObservers` helper because that helper randomizes both the seed and 
the voter count on every run, whereas this scenario needs a deterministic case 
per quorum size.
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to