Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
85 commits
Select commit Hold shift + click to select a range
acccb16
initial changes
jaykay12 May 15, 2026
e426014
testing
jaykay12 May 16, 2026
7b15791
working api
jaykay12 May 16, 2026
02c14b9
working setup
jaykay12 May 16, 2026
177d2c6
cleanup
jaykay12 May 16, 2026
95ace8d
cleanup
jaykay12 May 16, 2026
7dc167a
logging
jaykay12 May 16, 2026
1a32bb1
minor
jaykay12 May 16, 2026
6b6f536
Merge branch 'main' into SOLR-18248-list-tasks
jaykay12 May 19, 2026
d746e21
response model for 2nd API
jaykay12 May 19, 2026
df5c428
verifies for solr cloud
jaykay12 May 19, 2026
354d0f5
changes related to pojo & duplicate code removal
jaykay12 May 20, 2026
1cad09d
removed older interfaces
jaykay12 May 20, 2026
579925d
removing debug
jaykay12 May 20, 2026
eb1cd97
done
jaykay12 May 20, 2026
4e10720
self review
jaykay12 May 20, 2026
eb9b51b
added cl
jaykay12 May 20, 2026
adc7006
tidying done
jaykay12 May 20, 2026
996b45b
added apache license
jaykay12 May 20, 2026
f6cb8f7
tests
jaykay12 May 22, 2026
97e5afa
added 1 test
jaykay12 May 23, 2026
3d72214
added license
jaykay12 May 23, 2026
68eec35
test corrections
jaykay12 May 24, 2026
87204e2
minor tidy
jaykay12 May 24, 2026
930312b
test to check actual active/inactive
jaykay12 May 24, 2026
ba79375
Merge branch 'main' into SOLR-18248-list-tasks
jaykay12 May 28, 2026
199cb24
comments addressal
jaykay12 May 28, 2026
24ca810
comments addressed
jaykay12 May 28, 2026
c583c38
tidying it up
jaykay12 May 28, 2026
bb0f0f1
comments addressed
jaykay12 May 29, 2026
d0ddec6
tidy up
jaykay12 May 29, 2026
0905202
update
jaykay12 May 29, 2026
d08d788
minor
jaykay12 May 29, 2026
1b0b81d
Remove "breadcrumb" pointer, we only do it in one other place.
epugh May 29, 2026
200afba
checking
jaykay12 May 29, 2026
cd97aa6
Merge branch 'main' into SOLR-18248-list-tasks
jaykay12 Jun 2, 2026
d161485
this works
jaykay12 Jun 2, 2026
12e0a9c
commenting the remaining code & related tests for now
jaykay12 Jun 2, 2026
02ecda9
Merge branch 'main' into SOLR-18248-list-tasks
jaykay12 Jun 9, 2026
a8beb53
Merge branch 'main' into SOLR-18248-list-tasks
jaykay12 Jun 14, 2026
6c3ed49
removed commented code
jaykay12 Jun 14, 2026
1a6c5e3
pr ready again
jaykay12 Jun 14, 2026
4b16add
tidy up
jaykay12 Jun 14, 2026
96ad4f4
added license
jaykay12 Jun 14, 2026
6133beb
tidy forced
jaykay12 Jun 14, 2026
5d0d2ce
Merge branch 'main' into SOLR-18248-list-tasks
jaykay12 Jun 18, 2026
c85327f
fixed response format v1-list api
jaykay12 Jun 18, 2026
e128b41
changes in response of v1 api
jaykay12 Jun 18, 2026
6ee9400
Merge branch 'main' into SOLR-18248-cancel-tasks
jaykay12 Jun 30, 2026
a459177
Merge branch 'main' into SOLR-18248-cancel-tasks
jaykay12 Aug 22, 2026
1646d49
cl
jaykay12 Aug 22, 2026
775e6c8
Merge branch 'main' into SOLR-18248-cancel-tasks
jaykay12 Aug 24, 2026
035875e
cl
jaykay12 Aug 24, 2026
a0843da
contract
jaykay12 Aug 24, 2026
bc30205
Merge branch 'main' into SOLR-18248-cancel-tasks
jaykay12 Aug 28, 2026
a8a5e1d
changes
jaykay12 Aug 29, 2026
d4721e5
changes
jaykay12 Aug 29, 2026
e4e2ac1
minimal file
jaykay12 Aug 29, 2026
20a1f77
changes
jaykay12 Aug 29, 2026
b68dd6c
added licenses
jaykay12 Aug 29, 2026
f625a4c
tidy up
jaykay12 Aug 29, 2026
df41eee
response code
jaykay12 Aug 29, 2026
18de48a
cleanup
jaykay12 Aug 29, 2026
f6019e6
fixed tests
jaykay12 Aug 30, 2026
6f1dfac
test fixed
jaykay12 Aug 30, 2026
f56c06f
Add a unit test demonstrating 404 not working
epugh Aug 30, 2026
8f5112a
tests fixed
jaykay12 Aug 30, 2026
b50d552
tidying up
jaykay12 Aug 30, 2026
cc6f788
eric as author
jaykay12 Aug 30, 2026
b5dbd12
ref guide
jaykay12 Aug 30, 2026
adf3379
Connect task management to the query params page better.
epugh Aug 31, 2026
57e8316
simplify the text, and get away from weird "UUID" term everywhere.
epugh Aug 31, 2026
149e1cf
components was dead code before, so remove it now.
epugh Aug 31, 2026
2271766
Need seperate documentation for v1 and v2 responses.
epugh Aug 31, 2026
b8520ed
Maybe a bit heavy, but since we don't want to change the output forma…
epugh Aug 31, 2026
a31604f
adding more tests...
epugh Aug 31, 2026
75ca730
Javadocs don't need to restart java code paths. Keep them focused.
epugh Aug 31, 2026
832293f
Reduce our dependency on SolrTestCaseJ4
epugh Aug 31, 2026
f56cd9d
javadocs!
epugh Aug 31, 2026
f2f646d
one more turn of crank
epugh Aug 31, 2026
a5d21c4
Merge branch 'main' into SOLR-18248-cancel-tasks
jaykay12 Aug 31, 2026
a28d8e0
Merge branch 'main' into SOLR-18248-cancel-tasks
jaykay12 Sep 1, 2026
70c3a57
Merge branch 'main' into SOLR-18248-cancel-tasks
jaykay12 Sep 1, 2026
8b6a562
Merge branch 'main' into SOLR-18248-cancel-tasks
jaykay12 Sep 5, 2026
b55ee10
Merge branch 'main' into SOLR-18248-cancel-tasks
jaykay12 Sep 6, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions changelog/unreleased/SOLR-18248-cancel-tasks.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
title:
Migration of CancelTask V2 API to JAX-RS construct
type: changed
authors:
- name: Jalaz Kumar
- name: Eric Pugh
links:
- name: SOLR-18248
url: https://issues.apache.org/jira/browse/SOLR-18248
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,11 @@
import static org.apache.solr.client.api.util.Constants.INDEX_PATH_PREFIX;

import io.swagger.v3.oas.annotations.Operation;
import jakarta.ws.rs.DELETE;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.PathParam;
import org.apache.solr.client.api.model.CancelTaskResponse;
import org.apache.solr.client.api.model.ListActiveTaskResponse;
import org.apache.solr.client.api.model.TaskStatusResponse;
import org.apache.solr.client.api.util.StoreApiParameters;
Expand All @@ -48,4 +50,14 @@ interface Status {
tags = {"tasks"})
TaskStatusResponse getTaskStatus(@PathParam("taskID") String taskID) throws Exception;
}

@Path(INDEX_PATH_PREFIX + "/tasks/{taskID}")
interface Cancel {
@DELETE
@StoreApiParameters
@Operation(
summary = "Cancel any specific task",
tags = {"tasks"})
CancelTaskResponse cancelRunningTask(@PathParam("taskID") String taskID) throws Exception;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.apache.solr.client.api.model;

import com.fasterxml.jackson.annotation.JsonProperty;

/** Response body returned after a task cancellation request. */
public class CancelTaskResponse extends SolrJerseyResponse {

public enum CancellationStatus {
SUCCESS,
NOT_FOUND
}

@JsonProperty public CancelTaskResponse.CancellationStatus status;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.apache.solr.handler.admin.api;

import static org.apache.solr.security.PermissionNameProvider.Name.READ_PERM;

import jakarta.inject.Inject;
import org.apache.solr.api.JerseyResource;
import org.apache.solr.client.api.endpoint.TasksApi;
import org.apache.solr.client.api.model.CancelTaskResponse;
import org.apache.solr.common.SolrException;
import org.apache.solr.handler.component.ActiveTaskQuerySupport;
import org.apache.solr.jersey.PermissionName;
import org.apache.solr.request.SolrQueryRequest;
import org.apache.solr.search.CancellableCollector;

/** V2 API implementation for cancelling an active task. */
public class CancelTask extends JerseyResource implements TasksApi.Cancel {

private final SolrQueryRequest solrQueryRequest;

@Inject
public CancelTask(SolrQueryRequest solrQueryRequest) {
this.solrQueryRequest = solrQueryRequest;
}

@Override
@PermissionName(READ_PERM)
public CancelTaskResponse cancelRunningTask(String taskID) throws Exception {
Comment thread
epugh marked this conversation as resolved.
final CancelTaskResponse response = instantiateJerseyResponse(CancelTaskResponse.class);

boolean isTaskCancelled = ActiveTaskQuerySupport.cancelTask(solrQueryRequest, taskID);

if (isTaskCancelled) {
response.status = CancelTaskResponse.CancellationStatus.SUCCESS;
return response;
}
response.status = CancelTaskResponse.CancellationStatus.NOT_FOUND;
throw new SolrException(
SolrException.ErrorCode.NOT_FOUND, "Task with ID '" + taskID + "' not found");
}

public static boolean cancelTaskActiveOnThisShard(
SolrQueryRequest solrQueryRequest, String taskId) {
CancellableCollector cancellableTask =
solrQueryRequest.getCore().getCancellableQueryTracker().getCancellableTask(taskId);
if (cancellableTask != null) {
cancellableTask.cancel();
return true;
}
return false;
}
}

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

import static org.apache.solr.common.params.CommonParams.DISTRIB;
import static org.apache.solr.common.params.CommonParams.QT;
import static org.apache.solr.common.params.CommonParams.QUERY_UUID;
import static org.apache.solr.common.params.CommonParams.TASK_CHECK_UUID;

import java.util.ArrayList;
Expand All @@ -29,39 +30,51 @@
import org.apache.solr.common.params.ModifiableSolrParams;
import org.apache.solr.common.util.NamedList;
import org.apache.solr.core.CoreContainer;
import org.apache.solr.handler.admin.api.CancelTask;
import org.apache.solr.handler.admin.api.ListActiveTasks;
import org.apache.solr.request.SolrQueryRequest;
import org.apache.solr.response.SolrQueryResponse;

public class ActiveTaskQuerySupport {
private static final String ACTIVE_TASK_LIST_HANDLER_PATH = "/tasks/list";
private static final String CANCEL_TASK_HANDLER_PATH = "/tasks/cancel";

private ActiveTaskQuerySupport() {}

public static List<ActiveTaskDetails> listActiveTasks(SolrQueryRequest req) throws Exception {
return execute(req, null).taskList;
return execute(req, null, false).taskList;
}

public static boolean isTaskActive(SolrQueryRequest req, String taskId) throws Exception {
return execute(req, taskId).taskActive;
return execute(req, taskId, false).taskActive;
}

private static TaskQueryResult execute(SolrQueryRequest req, String taskId) throws Exception {
public static boolean cancelTask(SolrQueryRequest req, String taskId) throws Exception {
return execute(req, taskId, true).taskCancelled;
}

private static TaskQueryResult execute(
SolrQueryRequest req, String taskId, boolean isCancellationRequest) throws Exception {
if (!shouldDistributed(req)) {
return localResult(req, taskId);
return localResult(req, taskId, isCancellationRequest);
}
return distributedResult(req, taskId);
return distributedResult(req, taskId, isCancellationRequest);
}

private static TaskQueryResult localResult(SolrQueryRequest req, String taskId) {
private static TaskQueryResult localResult(
SolrQueryRequest req, String taskId, boolean isCancellationRequest) {
if (taskId != null) {
return new TaskQueryResult(List.of(), ListActiveTasks.isTaskActiveOnThisShard(req, taskId));
return (isCancellationRequest)
? new TaskQueryResult(
List.of(), false, CancelTask.cancelTaskActiveOnThisShard(req, taskId))
: new TaskQueryResult(
List.of(), ListActiveTasks.isTaskActiveOnThisShard(req, taskId), false);
}
return new TaskQueryResult(ListActiveTasks.getActiveTasksOnThisShard(req), false);
return new TaskQueryResult(ListActiveTasks.getActiveTasksOnThisShard(req), false, false);
}

private static TaskQueryResult distributedResult(SolrQueryRequest req, String taskId)
throws Exception {
private static TaskQueryResult distributedResult(
SolrQueryRequest req, String taskId, boolean isCancellationRequest) {
final ShardHandler shardHandler =
req.getCoreContainer().getShardHandlerFactory().getShardHandler();
final ResponseBuilder responseBuilder =
Expand All @@ -71,7 +84,7 @@ private static TaskQueryResult distributedResult(SolrQueryRequest req, String ta
if (!responseBuilder.isDistrib
|| responseBuilder.shards == null
|| responseBuilder.shards.length == 0) {
return localResult(req, taskId);
return localResult(req, taskId, isCancellationRequest);
}

final ShardRequest shardRequest = new ShardRequest();
Expand All @@ -81,9 +94,17 @@ private static TaskQueryResult distributedResult(SolrQueryRequest req, String ta

for (String shard : shardRequest.actualShards) {
ModifiableSolrParams params = new ModifiableSolrParams();
params.set(QT, ACTIVE_TASK_LIST_HANDLER_PATH);
if (isCancellationRequest) {
params.set(QT, CANCEL_TASK_HANDLER_PATH);
} else {
params.set(QT, ACTIVE_TASK_LIST_HANDLER_PATH);
}
if (taskId != null) {
params.set(TASK_CHECK_UUID, taskId);
if (isCancellationRequest) {
params.set(QUERY_UUID, taskId);
} else {
params.set(TASK_CHECK_UUID, taskId);
}
}
ShardHandler.setShardAttributesToParams(params, shardRequest.purpose);
shardHandler.submit(shardRequest, shard, params);
Expand All @@ -101,9 +122,11 @@ private static TaskQueryResult distributedResult(SolrQueryRequest req, String ta
}

if (taskId != null) {
return new TaskQueryResult(List.of(), mergeTaskStatus(shardRequest.responses));
return (isCancellationRequest)
? new TaskQueryResult(List.of(), false, mergeCancellationStatus(shardRequest.responses))
: new TaskQueryResult(List.of(), mergeTaskStatus(shardRequest.responses), false);
}
return new TaskQueryResult(mergeTaskList(shardRequest.responses), false);
return new TaskQueryResult(mergeTaskList(shardRequest.responses), false, false);
}

private static boolean shouldDistributed(SolrQueryRequest req) {
Expand All @@ -128,6 +151,25 @@ private static boolean mergeTaskStatus(List<ShardResponse> responses) {
return false;
}

// FRAGILE: matches TaskCancellationHandler's human-readable "status" message by substring, for
// both V1 and V2 (CancelTask calls this same method). Kept as-is since changing the V1 wire
// format is out of scope; see the matching FRAGILE note in
// TaskCancellationHandler.handleRequestBody().
private static boolean mergeCancellationStatus(List<ShardResponse> responses) {
for (ShardResponse shardResponse : responses) {
Object cancellationStatus = shardResponse.getSolrResponse().getResponse().get("status");
if (cancellationStatus instanceof Boolean && (Boolean) cancellationStatus) {
return true;
}

if (cancellationStatus instanceof String
&& ((String) cancellationStatus).contains("cancelled successfully")) {
return true;
}
}
return false;
}

@SuppressWarnings("unchecked")
private static List<ActiveTaskDetails> mergeTaskList(List<ShardResponse> responses) {
Map<String, String> mergedTasks = new LinkedHashMap<>();
Expand Down Expand Up @@ -156,10 +198,13 @@ private static List<ActiveTaskDetails> mergeTaskList(List<ShardResponse> respons
private static final class TaskQueryResult {
private final List<ActiveTaskDetails> taskList;
private final boolean taskActive;
private final boolean taskCancelled;

private TaskQueryResult(List<ActiveTaskDetails> taskList, boolean taskActive) {
private TaskQueryResult(
List<ActiveTaskDetails> taskList, boolean taskActive, boolean taskCancelled) {
this.taskList = taskList;
this.taskActive = taskActive;
this.taskCancelled = taskCancelled;
}
}
}
Loading