Search: When a search request failed completely (all shards fail) return a proper HTTP status code, closes #1035.

This commit is contained in:
kimchy 2011-06-15 16:28:53 +03:00
parent bbd73d5afa
commit db6f5a7146
5 changed files with 58 additions and 4 deletions

View File

@ -27,6 +27,7 @@ import org.elasticsearch.common.xcontent.ToXContent;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentBuilderString;
import org.elasticsearch.common.xcontent.XContentFactory;
import org.elasticsearch.rest.RestStatus;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.facet.Facets;
import org.elasticsearch.search.internal.InternalSearchResponse;
@ -67,6 +68,24 @@ public class SearchResponse implements ActionResponse, ToXContent {
this.shardFailures = shardFailures;
}
public RestStatus status() {
if (shardFailures.length == 0) {
return RestStatus.OK;
}
if (successfulShards == 0 && totalShards > 0) {
RestStatus status = shardFailures[0].status();
if (shardFailures.length > 1) {
for (int i = 1; i < shardFailures.length; i++) {
if (shardFailures[i].status().getStatus() >= 500) {
status = shardFailures[i].status();
}
}
}
return status;
}
return RestStatus.OK;
}
/**
* The search hits.
*/
@ -216,6 +235,7 @@ public class SearchResponse implements ActionResponse, ToXContent {
static final XContentBuilderString SUCCESSFUL = new XContentBuilderString("successful");
static final XContentBuilderString FAILED = new XContentBuilderString("failed");
static final XContentBuilderString FAILURES = new XContentBuilderString("failures");
static final XContentBuilderString STATUS = new XContentBuilderString("status");
static final XContentBuilderString INDEX = new XContentBuilderString("index");
static final XContentBuilderString SHARD = new XContentBuilderString("shard");
static final XContentBuilderString REASON = new XContentBuilderString("reason");
@ -242,6 +262,7 @@ public class SearchResponse implements ActionResponse, ToXContent {
builder.field(Fields.INDEX, shardFailure.shard().index());
builder.field(Fields.SHARD, shardFailure.shard().shardId());
}
builder.field(Fields.STATUS, shardFailure.status().getStatus());
builder.field(Fields.REASON, shardFailure.reason());
builder.endObject();
}

View File

@ -19,11 +19,13 @@
package org.elasticsearch.action.search;
import org.elasticsearch.ElasticSearchException;
import org.elasticsearch.ExceptionsHelper;
import org.elasticsearch.action.ShardOperationFailedException;
import org.elasticsearch.common.Nullable;
import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.common.io.stream.StreamOutput;
import org.elasticsearch.rest.RestStatus;
import org.elasticsearch.search.SearchException;
import org.elasticsearch.search.SearchShardTarget;
@ -44,6 +46,8 @@ public class ShardSearchFailure implements ShardOperationFailedException {
private String reason;
private RestStatus status;
private ShardSearchFailure() {
}
@ -53,6 +57,11 @@ public class ShardSearchFailure implements ShardOperationFailedException {
if (actual != null && actual instanceof SearchException) {
this.shardTarget = ((SearchException) actual).shard();
}
if (actual != null && actual instanceof ElasticSearchException) {
status = ((ElasticSearchException) t).status();
} else {
status = RestStatus.INTERNAL_SERVER_ERROR;
}
this.reason = ExceptionsHelper.detailedMessage(t);
}
@ -62,12 +71,16 @@ public class ShardSearchFailure implements ShardOperationFailedException {
}
/**
* The search shard target the failure occured on.
* The search shard target the failure occurred on.
*/
@Nullable public SearchShardTarget shard() {
return this.shardTarget;
}
public RestStatus status() {
return this.status;
}
/**
* The index the search failed on.
*/
@ -110,6 +123,7 @@ public class ShardSearchFailure implements ShardOperationFailedException {
shardTarget = readSearchShardTarget(in);
}
reason = in.readUTF();
status = RestStatus.readFrom(in);
}
@Override public void writeTo(StreamOutput out) throws IOException {
@ -120,5 +134,6 @@ public class ShardSearchFailure implements ShardOperationFailedException {
shardTarget.writeTo(out);
}
out.writeUTF(reason);
RestStatus.writeTo(out, status);
}
}

View File

@ -19,6 +19,11 @@
package org.elasticsearch.rest;
import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.common.io.stream.StreamOutput;
import java.io.IOException;
public enum RestStatus {
/**
* The client SHOULD continue with its request. This interim response is used to inform the client that the
@ -477,4 +482,12 @@ public enum RestStatus {
public int getStatus() {
return status;
}
public static RestStatus readFrom(StreamInput in) throws IOException {
return RestStatus.valueOf(in.readUTF());
}
public static void writeTo(StreamOutput out, RestStatus status) throws IOException {
out.writeUTF(status.name());
}
}

View File

@ -104,7 +104,7 @@ public class RestSearchAction extends BaseRestHandler {
builder.startObject();
response.toXContent(builder, request);
builder.endObject();
channel.sendResponse(new XContentRestResponse(request, OK, builder));
channel.sendResponse(new XContentRestResponse(request, response.status(), builder));
} catch (Exception e) {
if (logger.isDebugEnabled()) {
logger.debug("failed to execute search (building response)", e);

View File

@ -27,7 +27,12 @@ import org.elasticsearch.client.Client;
import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.rest.*;
import org.elasticsearch.rest.BaseRestHandler;
import org.elasticsearch.rest.RestChannel;
import org.elasticsearch.rest.RestController;
import org.elasticsearch.rest.RestRequest;
import org.elasticsearch.rest.XContentRestResponse;
import org.elasticsearch.rest.XContentThrowableRestResponse;
import org.elasticsearch.search.Scroll;
import java.io.IOException;
@ -86,7 +91,7 @@ public class RestSearchScrollAction extends BaseRestHandler {
builder.startObject();
response.toXContent(builder, request);
builder.endObject();
channel.sendResponse(new XContentRestResponse(request, OK, builder));
channel.sendResponse(new XContentRestResponse(request, response.status(), builder));
} catch (Exception e) {
onFailure(e);
}