Skip to content

Commit f266eb3

Browse files
authored
Deprecate returning 408 for a server timeout on _cluster/health (#78180)
Add a deprecation warning and a system property es.cluster_health.request_timeout_200 to opt in for returning 200 which will be the default in 8.0.0 Fixes #70849
1 parent 8bcbebb commit f266eb3

File tree

3 files changed

+50
-3
lines changed

3 files changed

+50
-3
lines changed

client/rest-high-level/src/test/java/org/elasticsearch/client/ClusterClientIT.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -303,6 +303,9 @@ public void testClusterHealthNotFoundIndex() throws IOException {
303303
assertThat(response.status(), equalTo(RestStatus.REQUEST_TIMEOUT));
304304
assertThat(response.getStatus(), equalTo(ClusterHealthStatus.RED));
305305
assertNoIndices(response);
306+
assertWarnings("The HTTP status code for a cluster health timeout will be changed from 408 to 200 in a " +
307+
"future version. Set the [es.cluster_health.request_timeout_200] system property to [true] to suppress this message and " +
308+
"opt in to the future behaviour now.");
306309
}
307310

308311
public void testRemoteInfo() throws Exception {

server/src/main/java/org/elasticsearch/action/admin/cluster/health/ClusterHealthResponse.java

Lines changed: 38 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
import org.elasticsearch.cluster.health.ClusterHealthStatus;
1414
import org.elasticsearch.cluster.health.ClusterIndexHealth;
1515
import org.elasticsearch.cluster.health.ClusterStateHealth;
16+
import org.elasticsearch.common.logging.DeprecationLogger;
1617
import org.elasticsearch.xcontent.ParseField;
1718
import org.elasticsearch.common.Strings;
1819
import org.elasticsearch.common.io.stream.StreamInput;
@@ -24,6 +25,7 @@
2425
import org.elasticsearch.xcontent.XContentBuilder;
2526
import org.elasticsearch.xcontent.XContentParser;
2627
import org.elasticsearch.rest.RestStatus;
28+
import org.elasticsearch.rest.action.search.RestSearchAction;
2729

2830
import java.io.IOException;
2931
import java.util.HashMap;
@@ -55,6 +57,7 @@ public class ClusterHealthResponse extends ActionResponse implements StatusToXCo
5557
private static final String INITIALIZING_SHARDS = "initializing_shards";
5658
private static final String UNASSIGNED_SHARDS = "unassigned_shards";
5759
private static final String INDICES = "indices";
60+
private static final DeprecationLogger deprecationLogger = DeprecationLogger.getLogger(RestSearchAction.class);
5861

5962
private static final ConstructingObjectParser<ClusterHealthResponse, Void> PARSER =
6063
new ConstructingObjectParser<>("cluster_health_response", true,
@@ -97,7 +100,11 @@ public class ClusterHealthResponse extends ActionResponse implements StatusToXCo
97100
});
98101

99102
private static final ObjectParser.NamedObjectParser<ClusterIndexHealth, Void> INDEX_PARSER =
100-
(XContentParser parser, Void context, String index) -> ClusterIndexHealth.innerFromXContent(parser, index);
103+
(XContentParser parser, Void context, String index) -> ClusterIndexHealth.innerFromXContent(parser, index);
104+
private static final String ES_CLUSTER_HEALTH_REQUEST_TIMEOUT_200_KEY = "es.cluster_health.request_timeout_200";
105+
static final String CLUSTER_HEALTH_REQUEST_TIMEOUT_DEPRECATION_MSG = "The HTTP status code for a cluster health timeout " +
106+
"will be changed from 408 to 200 in a future version. Set the [" + ES_CLUSTER_HEALTH_REQUEST_TIMEOUT_200_KEY + "] " +
107+
"system property to [true] to suppress this message and opt in to the future behaviour now.";
101108

102109
static {
103110
// ClusterStateHealth fields
@@ -130,8 +137,15 @@ public class ClusterHealthResponse extends ActionResponse implements StatusToXCo
130137
private boolean timedOut = false;
131138
private ClusterStateHealth clusterStateHealth;
132139
private ClusterHealthStatus clusterHealthStatus;
140+
private boolean esClusterHealthRequestTimeout200 = readEsClusterHealthRequestTimeout200FromProperty();
133141

134-
public ClusterHealthResponse() {}
142+
public ClusterHealthResponse() {
143+
}
144+
145+
/** For the testing of opting in for the 200 status code without setting a system property */
146+
ClusterHealthResponse(boolean esClusterHealthRequestTimeout200) {
147+
this.esClusterHealthRequestTimeout200 = esClusterHealthRequestTimeout200;
148+
}
135149

136150
public ClusterHealthResponse(StreamInput in) throws IOException {
137151
super(in);
@@ -299,7 +313,15 @@ public String toString() {
299313

300314
@Override
301315
public RestStatus status() {
302-
return isTimedOut() ? RestStatus.REQUEST_TIMEOUT : RestStatus.OK;
316+
if (isTimedOut() == false) {
317+
return RestStatus.OK;
318+
}
319+
if (esClusterHealthRequestTimeout200) {
320+
return RestStatus.OK;
321+
} else {
322+
deprecationLogger.compatibleCritical("cluster_health_request_timeout", CLUSTER_HEALTH_REQUEST_TIMEOUT_DEPRECATION_MSG);
323+
return RestStatus.REQUEST_TIMEOUT;
324+
}
303325
}
304326

305327
@Override
@@ -359,4 +381,17 @@ public int hashCode() {
359381
return Objects.hash(clusterName, numberOfPendingTasks, numberOfInFlightFetch, delayedUnassignedShards, taskMaxWaitingTime,
360382
timedOut, clusterStateHealth, clusterHealthStatus);
361383
}
384+
385+
private static boolean readEsClusterHealthRequestTimeout200FromProperty() {
386+
String property = System.getProperty(ES_CLUSTER_HEALTH_REQUEST_TIMEOUT_200_KEY);
387+
if (property == null) {
388+
return false;
389+
}
390+
if (Boolean.parseBoolean(property)) {
391+
return true;
392+
} else {
393+
throw new IllegalArgumentException(ES_CLUSTER_HEALTH_REQUEST_TIMEOUT_200_KEY + " can only be unset or [true] but was ["
394+
+ property + "]");
395+
}
396+
}
362397
}

server/src/test/java/org/elasticsearch/action/admin/cluster/health/ClusterHealthResponsesTests.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,12 +48,21 @@ public void testIsTimeout() {
4848
res.setTimedOut(randomBoolean());
4949
if (res.isTimedOut()) {
5050
assertEquals(RestStatus.REQUEST_TIMEOUT, res.status());
51+
assertWarnings(ClusterHealthResponse.CLUSTER_HEALTH_REQUEST_TIMEOUT_DEPRECATION_MSG);
5152
} else {
5253
assertEquals(RestStatus.OK, res.status());
5354
}
5455
}
5556
}
5657

58+
public void testTimeoutReturns200IfOptedIn() {
59+
ClusterHealthResponse res = new ClusterHealthResponse(true);
60+
for (int i = 0; i < 5; i++) {
61+
res.setTimedOut(randomBoolean());
62+
assertEquals(RestStatus.OK, res.status());
63+
}
64+
}
65+
5766
public void testClusterHealth() throws IOException {
5867
ClusterState clusterState = ClusterState.builder(ClusterName.CLUSTER_NAME_SETTING.getDefault(Settings.EMPTY)).build();
5968
int pendingTasks = randomIntBetween(0, 200);

0 commit comments

Comments
 (0)