Skip to content

Commit 471aa6a

Browse files
jainankitkjavanna
authored andcommitted
Fixing 503 Service Unavailable errors during fetch phase (#39086)
When ESRejectedExecutionException gets thrown on the coordinating node while trying to fetch hits, the resulting exception will hold no shard failures, hence `503` is used as the response status code. In that case, `429` should be returned instead. Also, the status code should be taken from the cause if available whenever there are no shard failures instead of blindly returning `503` like we currently do. Closes #38586
1 parent 8925a2c commit 471aa6a

File tree

2 files changed

+40
-2
lines changed

2 files changed

+40
-2
lines changed

server/src/main/java/org/elasticsearch/action/search/SearchPhaseExecutionException.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -85,8 +85,9 @@ private static Throwable deduplicateCause(Throwable cause, ShardSearchFailure[]
8585
@Override
8686
public RestStatus status() {
8787
if (shardFailures.length == 0) {
88-
// if no successful shards, it means no active shards, so just return SERVICE_UNAVAILABLE
89-
return RestStatus.SERVICE_UNAVAILABLE;
88+
// if no successful shards, the failure can be due to EsRejectedExecutionException during fetch phase
89+
// on coordinator node. so get the status from cause instead of returning SERVICE_UNAVAILABLE blindly
90+
return getCause() == null ? RestStatus.SERVICE_UNAVAILABLE : ExceptionsHelper.status(getCause());
9091
}
9192
RestStatus status = shardFailures[0].status();
9293
if (shardFailures.length > 1) {

server/src/test/java/org/elasticsearch/action/search/SearchPhaseExecutionExceptionTests.java

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,13 +25,15 @@
2525
import org.elasticsearch.common.ParsingException;
2626
import org.elasticsearch.common.Strings;
2727
import org.elasticsearch.common.bytes.BytesReference;
28+
import org.elasticsearch.common.util.concurrent.EsRejectedExecutionException;
2829
import org.elasticsearch.common.xcontent.ToXContent;
2930
import org.elasticsearch.common.xcontent.XContent;
3031
import org.elasticsearch.common.xcontent.XContentParser;
3132
import org.elasticsearch.common.xcontent.XContentType;
3233
import org.elasticsearch.index.shard.IndexShardClosedException;
3334
import org.elasticsearch.index.shard.ShardId;
3435
import org.elasticsearch.indices.InvalidIndexTemplateException;
36+
import org.elasticsearch.rest.RestStatus;
3537
import org.elasticsearch.search.SearchShardTarget;
3638
import org.elasticsearch.test.ESTestCase;
3739

@@ -121,4 +123,39 @@ public void testToAndFromXContent() throws IOException {
121123
// SearchPhaseExecutionException has no cause field
122124
assertNull(parsedException.getCause());
123125
}
126+
127+
public void testPhaseFailureWithoutSearchShardFailure() {
128+
final ShardSearchFailure[] searchShardFailures = new ShardSearchFailure[0];
129+
final String phase = randomFrom("fetch", "search", "other");
130+
SearchPhaseExecutionException actual = new SearchPhaseExecutionException(phase, "unexpected failures",
131+
new EsRejectedExecutionException("ES rejected execution of fetch phase"), searchShardFailures);
132+
133+
assertEquals(actual.status(), RestStatus.TOO_MANY_REQUESTS);
134+
}
135+
136+
public void testPhaseFailureWithoutSearchShardFailureAndCause() {
137+
final ShardSearchFailure[] searchShardFailures = new ShardSearchFailure[0];
138+
final String phase = randomFrom("fetch", "search", "other");
139+
SearchPhaseExecutionException actual = new SearchPhaseExecutionException(phase, "unexpected failures", null, searchShardFailures);
140+
141+
assertEquals(actual.status(), RestStatus.SERVICE_UNAVAILABLE);
142+
}
143+
144+
public void testPhaseFailureWithSearchShardFailure() {
145+
final ShardSearchFailure[] shardSearchFailures = new ShardSearchFailure[randomIntBetween(1, 5)];
146+
for (int i = 0; i < shardSearchFailures.length; i++) {
147+
Exception cause = randomFrom(
148+
new ParsingException(1, 2, "foobar", null),
149+
new InvalidIndexTemplateException("foo", "bar")
150+
);
151+
shardSearchFailures[i] = new ShardSearchFailure(cause, new SearchShardTarget("node_" + i,
152+
new ShardId("test", "_na_", i), null, OriginalIndices.NONE));
153+
}
154+
155+
final String phase = randomFrom("fetch", "search", "other");
156+
SearchPhaseExecutionException actual = new SearchPhaseExecutionException(phase, "unexpected failures",
157+
new EsRejectedExecutionException("ES rejected execution of fetch phase"), shardSearchFailures);
158+
159+
assertEquals(actual.status(), RestStatus.BAD_REQUEST);
160+
}
124161
}

0 commit comments

Comments
 (0)