forked from elastic/elasticsearch
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add capability to stop async query on demand
- Loading branch information
Showing
9 changed files
with
242 additions
and
2 deletions.
There are no files selected for viewing
64 changes: 64 additions & 0 deletions
64
x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/async/AsyncStopRequest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
/* | ||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one | ||
* or more contributor license agreements. Licensed under the Elastic License | ||
* 2.0; you may not use this file except in compliance with the Elastic License | ||
* 2.0. | ||
*/ | ||
package org.elasticsearch.xpack.core.async; | ||
|
||
import org.elasticsearch.action.ActionRequest; | ||
import org.elasticsearch.action.ActionRequestValidationException; | ||
import org.elasticsearch.common.io.stream.StreamInput; | ||
import org.elasticsearch.common.io.stream.StreamOutput; | ||
|
||
import java.io.IOException; | ||
import java.util.Objects; | ||
|
||
public class AsyncStopRequest extends ActionRequest { | ||
private final String id; | ||
|
||
/** | ||
* Creates a new request | ||
* | ||
* @param id The id of the search progress request. | ||
*/ | ||
public AsyncStopRequest(String id) { | ||
this.id = id; | ||
} | ||
|
||
public AsyncStopRequest(StreamInput in) throws IOException { | ||
super(in); | ||
this.id = in.readString(); | ||
} | ||
|
||
@Override | ||
public void writeTo(StreamOutput out) throws IOException { | ||
super.writeTo(out); | ||
out.writeString(id); | ||
} | ||
|
||
@Override | ||
public ActionRequestValidationException validate() { | ||
return null; | ||
} | ||
|
||
/** | ||
* Returns the id of the async search. | ||
*/ | ||
public String getId() { | ||
return id; | ||
} | ||
|
||
@Override | ||
public boolean equals(Object o) { | ||
if (this == o) return true; | ||
if (o == null || getClass() != o.getClass()) return false; | ||
AsyncStopRequest request = (AsyncStopRequest) o; | ||
return Objects.equals(id, request.id); | ||
} | ||
|
||
@Override | ||
public int hashCode() { | ||
return Objects.hash(id); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
22 changes: 22 additions & 0 deletions
22
...ck/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/action/EsqlAsyncStopAction.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
/* | ||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one | ||
* or more contributor license agreements. Licensed under the Elastic License | ||
* 2.0; you may not use this file except in compliance with the Elastic License | ||
* 2.0. | ||
*/ | ||
|
||
package org.elasticsearch.xpack.esql.action; | ||
|
||
import org.elasticsearch.action.ActionType; | ||
import org.elasticsearch.xpack.core.esql.EsqlAsyncActionNames; | ||
|
||
public class EsqlAsyncStopAction extends ActionType<EsqlQueryResponse> { | ||
|
||
public static final EsqlAsyncStopAction INSTANCE = new EsqlAsyncStopAction(); | ||
|
||
public static final String NAME = EsqlAsyncActionNames.ESQL_ASYNC_STOP_ACTION_NAME; | ||
|
||
private EsqlAsyncStopAction() { | ||
super(NAME); | ||
} | ||
} |
47 changes: 47 additions & 0 deletions
47
...lugin/esql/src/main/java/org/elasticsearch/xpack/esql/action/RestEsqlStopAsyncAction.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
/* | ||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one | ||
* or more contributor license agreements. Licensed under the Elastic License | ||
* 2.0; you may not use this file except in compliance with the Elastic License | ||
* 2.0. | ||
*/ | ||
|
||
package org.elasticsearch.xpack.esql.action; | ||
|
||
import org.elasticsearch.client.internal.node.NodeClient; | ||
import org.elasticsearch.rest.BaseRestHandler; | ||
import org.elasticsearch.rest.RestRequest; | ||
import org.elasticsearch.rest.Scope; | ||
import org.elasticsearch.rest.ServerlessScope; | ||
import org.elasticsearch.rest.action.RestRefCountedChunkedToXContentListener; | ||
import org.elasticsearch.xpack.core.async.AsyncStopRequest; | ||
|
||
import java.util.List; | ||
import java.util.Set; | ||
|
||
import static org.elasticsearch.rest.RestRequest.Method.POST; | ||
import static org.elasticsearch.xpack.esql.action.EsqlQueryResponse.DROP_NULL_COLUMNS_OPTION; | ||
import static org.elasticsearch.xpack.esql.formatter.TextFormat.URL_PARAM_DELIMITER; | ||
|
||
@ServerlessScope(Scope.PUBLIC) | ||
public class RestEsqlStopAsyncAction extends BaseRestHandler { | ||
@Override | ||
public List<Route> routes() { | ||
return List.of(new Route(POST, "/_query/async/{id}/stop")); | ||
} | ||
|
||
@Override | ||
public String getName() { | ||
return "esql_async_stop"; | ||
} | ||
|
||
@Override | ||
protected RestChannelConsumer prepareRequest(RestRequest request, NodeClient client) { | ||
AsyncStopRequest get = new AsyncStopRequest(request.param("id")); | ||
return channel -> client.execute(EsqlAsyncStopAction.INSTANCE, get, new RestRefCountedChunkedToXContentListener<>(channel)); | ||
} | ||
|
||
@Override | ||
protected Set<String> responseParams() { | ||
return Set.of(URL_PARAM_DELIMITER, DROP_NULL_COLUMNS_OPTION); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
83 changes: 83 additions & 0 deletions
83
.../esql/src/main/java/org/elasticsearch/xpack/esql/plugin/TransportEsqlAsyncStopAction.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
/* | ||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one | ||
* or more contributor license agreements. Licensed under the Elastic License | ||
* 2.0; you may not use this file except in compliance with the Elastic License | ||
* 2.0. | ||
*/ | ||
|
||
package org.elasticsearch.xpack.esql.plugin; | ||
|
||
import org.elasticsearch.action.ActionListener; | ||
import org.elasticsearch.action.ActionListenerResponseHandler; | ||
import org.elasticsearch.action.support.ActionFilters; | ||
import org.elasticsearch.action.support.HandledTransportAction; | ||
import org.elasticsearch.cluster.node.DiscoveryNode; | ||
import org.elasticsearch.cluster.service.ClusterService; | ||
import org.elasticsearch.common.util.concurrent.EsExecutors; | ||
import org.elasticsearch.compute.data.BlockFactory; | ||
import org.elasticsearch.injection.guice.Inject; | ||
import org.elasticsearch.tasks.Task; | ||
import org.elasticsearch.transport.TransportService; | ||
import org.elasticsearch.xpack.core.async.AsyncExecutionId; | ||
import org.elasticsearch.xpack.core.async.AsyncStopRequest; | ||
import org.elasticsearch.xpack.core.async.GetAsyncResultRequest; | ||
import org.elasticsearch.xpack.esql.action.EsqlAsyncStopAction; | ||
import org.elasticsearch.xpack.esql.action.EsqlQueryResponse; | ||
|
||
/** | ||
* This action will stop running async request and collect the results. | ||
* If the request is already finished, it will do the same thing as the regular async get. | ||
*/ | ||
public class TransportEsqlAsyncStopAction extends HandledTransportAction<AsyncStopRequest, EsqlQueryResponse> { | ||
|
||
private final TransportEsqlQueryAction queryAction; | ||
private final TransportEsqlAsyncGetResultsAction getResultsAction; | ||
private final BlockFactory blockFactory; | ||
private final ClusterService clusterService; | ||
private final TransportService transportService; | ||
|
||
@Inject | ||
public TransportEsqlAsyncStopAction( | ||
TransportService transportService, | ||
ClusterService clusterService, | ||
ActionFilters actionFilters, | ||
TransportEsqlQueryAction queryAction, | ||
TransportEsqlAsyncGetResultsAction getResultsAction, | ||
BlockFactory blockFactory | ||
) { | ||
super(EsqlAsyncStopAction.NAME, transportService, actionFilters, AsyncStopRequest::new, EsExecutors.DIRECT_EXECUTOR_SERVICE); | ||
this.queryAction = queryAction; | ||
this.getResultsAction = getResultsAction; | ||
this.blockFactory = blockFactory; | ||
this.transportService = transportService; | ||
this.clusterService = clusterService; | ||
} | ||
|
||
@Override | ||
protected void doExecute(Task task, AsyncStopRequest request, ActionListener<EsqlQueryResponse> listener) { | ||
AsyncExecutionId searchId = AsyncExecutionId.decode(request.getId()); | ||
DiscoveryNode node = clusterService.state().nodes().get(searchId.getTaskId().getNodeId()); | ||
if (clusterService.localNode().getId().equals(searchId.getTaskId().getNodeId()) || node == null) { | ||
stopQueryAndReturnResult(task, request, listener); | ||
} else { | ||
transportService.sendRequest( | ||
node, | ||
EsqlAsyncStopAction.NAME, | ||
request, | ||
new ActionListenerResponseHandler<>(listener, EsqlQueryResponse.reader(blockFactory), EsExecutors.DIRECT_EXECUTOR_SERVICE) | ||
); | ||
} | ||
} | ||
|
||
private void stopQueryAndReturnResult(Task task, AsyncStopRequest request, ActionListener<EsqlQueryResponse> listener) { | ||
var asyncListener = queryAction.getAsyncListener(request.getId()); | ||
if (asyncListener == null) { | ||
// This should mean one of the two things: either bad request ID, or the query has already finished | ||
// In both cases, let regular async get deal with it. | ||
getResultsAction.execute(task, new GetAsyncResultRequest(request.getId()), listener); | ||
return; | ||
} | ||
asyncListener.addListener(listener); | ||
// TODO: send the finish signal to the source | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters