Skip to content

Commit fe18a67

Browse files
authored
Make TransportAddVotingConfigExclusionsAction retryable (#98568)
The docs for this API say the following: > If the API fails, you can safely retry it. Only a successful response > guarantees that the node has been removed from the voting > configuration and will not be reinstated. Unfortunately this isn't true today: if the request adds no exclusions then we do not wait before responding. This commit makes the API wait until all exclusions are really applied. Backport of #98386, plus the test changes from #98146 and #98356.
1 parent bb57a0c commit fe18a67

File tree

3 files changed

+227
-194
lines changed

3 files changed

+227
-194
lines changed

server/src/main/java/org/elasticsearch/action/admin/cluster/configuration/TransportAddVotingConfigExclusionsAction.java

Lines changed: 14 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,9 @@
3636
import org.elasticsearch.threadpool.ThreadPool;
3737
import org.elasticsearch.transport.TransportService;
3838

39+
import java.util.HashSet;
3940
import java.util.Set;
4041
import java.util.function.Predicate;
41-
import java.util.stream.Collectors;
4242

4343
public class TransportAddVotingConfigExclusionsAction extends TransportMasterNodeAction<
4444
AddVotingConfigExclusionsRequest,
@@ -99,13 +99,14 @@ protected void masterOperation(
9999

100100
clusterService.submitStateUpdateTask("add-voting-config-exclusions", new ClusterStateUpdateTask(Priority.URGENT) {
101101

102-
private Set<VotingConfigExclusion> resolvedExclusions;
103-
104102
@Override
105103
public ClusterState execute(ClusterState currentState) {
106-
assert resolvedExclusions == null : resolvedExclusions;
107104
final int finalMaxVotingConfigExclusions = TransportAddVotingConfigExclusionsAction.this.maxVotingConfigExclusions;
108-
resolvedExclusions = resolveVotingConfigExclusionsAndCheckMaximum(request, currentState, finalMaxVotingConfigExclusions);
105+
final Set<VotingConfigExclusion> resolvedExclusions = resolveVotingConfigExclusionsAndCheckMaximum(
106+
request,
107+
currentState,
108+
finalMaxVotingConfigExclusions
109+
);
109110

110111
final CoordinationMetadata.Builder builder = CoordinationMetadata.builder(currentState.coordinationMetadata());
111112
resolvedExclusions.forEach(builder::addVotingConfigExclusion);
@@ -130,13 +131,13 @@ public void clusterStateProcessed(String source, ClusterState oldState, ClusterS
130131
threadPool.getThreadContext()
131132
);
132133

133-
final Set<String> excludedNodeIds = resolvedExclusions.stream()
134-
.map(VotingConfigExclusion::getNodeId)
135-
.collect(Collectors.toSet());
136-
137134
final Predicate<ClusterState> allNodesRemoved = clusterState -> {
138-
final Set<String> votingConfigNodeIds = clusterState.getLastCommittedConfiguration().getNodeIds();
139-
return excludedNodeIds.stream().noneMatch(votingConfigNodeIds::contains);
135+
final Set<String> votingConfigNodeIds = new HashSet<>();
136+
votingConfigNodeIds.addAll(clusterState.getLastCommittedConfiguration().getNodeIds());
137+
votingConfigNodeIds.addAll(clusterState.getLastAcceptedConfiguration().getNodeIds());
138+
return clusterState.getVotingConfigExclusions()
139+
.stream()
140+
.noneMatch(votingConfigExclusion -> votingConfigNodeIds.contains(votingConfigExclusion.getNodeId()));
140141
};
141142

142143
final Listener clusterStateListener = new Listener() {
@@ -148,20 +149,14 @@ public void onNewClusterState(ClusterState state) {
148149
@Override
149150
public void onClusterServiceClose() {
150151
listener.onFailure(
151-
new ElasticsearchException(
152-
"cluster service closed while waiting for voting config exclusions "
153-
+ resolvedExclusions
154-
+ " to take effect"
155-
)
152+
new ElasticsearchException("cluster service closed while waiting for voting config exclusions to take effect")
156153
);
157154
}
158155

159156
@Override
160157
public void onTimeout(TimeValue timeout) {
161158
listener.onFailure(
162-
new ElasticsearchTimeoutException(
163-
"timed out waiting for voting config exclusions " + resolvedExclusions + " to take effect"
164-
)
159+
new ElasticsearchTimeoutException("timed out waiting for voting config exclusions to take effect")
165160
);
166161
}
167162
};

0 commit comments

Comments
 (0)