-
Notifications
You must be signed in to change notification settings - Fork 24.9k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[Transform] Improve force stop robustness in case of an error (#51072)
If a transform config got lost (e.g. because the internal index disappeared) tasks could not be stopped using transform API. This change makes it possible to stop transforms without a config, meaning to remove the background task. In order to do so force must be set to true.
- Loading branch information
Hendrik Muhs
committed
Jan 17, 2020
1 parent
a0bc9ee
commit 0f61ffe
Showing
6 changed files
with
238 additions
and
78 deletions.
There are no files selected for viewing
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
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
115 changes: 115 additions & 0 deletions
115
...ts/src/test/java/org/elasticsearch/xpack/transform/integration/TransformRobustnessIT.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,115 @@ | ||
/* | ||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one | ||
* or more contributor license agreements. Licensed under the Elastic License; | ||
* you may not use this file except in compliance with the Elastic License. | ||
*/ | ||
|
||
package org.elasticsearch.xpack.transform.integration; | ||
|
||
import org.elasticsearch.client.Request; | ||
import org.elasticsearch.client.ResponseException; | ||
import org.elasticsearch.xpack.core.transform.TransformField; | ||
import org.elasticsearch.xpack.core.transform.transforms.persistence.TransformInternalIndexConstants; | ||
|
||
import java.io.IOException; | ||
import java.util.Map; | ||
import java.util.Map.Entry; | ||
|
||
import static org.hamcrest.Matchers.containsString; | ||
import static org.hamcrest.Matchers.equalTo; | ||
|
||
public class TransformRobustnessIT extends TransformRestTestCase { | ||
|
||
public void testTaskRemovalAfterInternalIndexGotDeleted() throws Exception { | ||
String indexName = "continuous_reviews"; | ||
createReviewsIndex(indexName); | ||
String transformId = "simple_continuous_pivot"; | ||
String transformIndex = "pivot_reviews_continuous"; | ||
final Request createTransformRequest = new Request("PUT", TransformField.REST_BASE_PATH_TRANSFORMS + transformId); | ||
String config = "{" | ||
+ " \"source\": {\"index\":\"" | ||
+ indexName | ||
+ "\"}," | ||
+ " \"dest\": {\"index\":\"" | ||
+ transformIndex | ||
+ "\"}," | ||
+ " \"frequency\": \"1s\"," | ||
+ " \"sync\": {\"time\": {\"field\": \"timestamp\", \"delay\": \"1s\"}}," | ||
+ " \"pivot\": {" | ||
+ " \"group_by\": {" | ||
+ " \"reviewer\": {" | ||
+ " \"terms\": {" | ||
+ " \"field\": \"user_id\"" | ||
+ " } } }," | ||
+ " \"aggregations\": {" | ||
+ " \"avg_rating\": {" | ||
+ " \"avg\": {" | ||
+ " \"field\": \"stars\"" | ||
+ " } } } }" | ||
+ "}"; | ||
createTransformRequest.setJsonEntity(config); | ||
Map<String, Object> createTransformResponse = entityAsMap(client().performRequest(createTransformRequest)); | ||
assertThat(createTransformResponse.get("acknowledged"), equalTo(Boolean.TRUE)); | ||
assertEquals(1, getTransforms().size()); | ||
// there shouldn't be a task yet | ||
assertEquals(0, getNumberOfTransformTasks()); | ||
startAndWaitForContinuousTransform(transformId, transformIndex, null); | ||
assertTrue(indexExists(transformIndex)); | ||
|
||
// a task exists | ||
assertEquals(1, getNumberOfTransformTasks()); | ||
// get and check some users | ||
assertOnePivotValue(transformIndex + "/_search?q=reviewer:user_0", 3.776978417); | ||
assertOnePivotValue(transformIndex + "/_search?q=reviewer:user_5", 3.72); | ||
assertNotNull(getTransformState(transformId)); | ||
|
||
assertEquals(1, getTransforms().size()); | ||
|
||
// delete the transform index | ||
beEvilAndDeleteTheTransformIndex(); | ||
// transform is gone | ||
assertEquals(0, getTransforms().size()); | ||
// but the task is still there | ||
assertEquals(1, getNumberOfTransformTasks()); | ||
|
||
Request stopTransformRequest = new Request("POST", TransformField.REST_BASE_PATH_TRANSFORMS + transformId + "/_stop"); | ||
ResponseException e = expectThrows(ResponseException.class, () -> client().performRequest(stopTransformRequest)); | ||
|
||
assertEquals(409, e.getResponse().getStatusLine().getStatusCode()); | ||
assertThat( | ||
e.getMessage(), | ||
containsString("Detected transforms with no config [" + transformId + "]. Use force to stop/delete them.") | ||
); | ||
stopTransformRequest.addParameter(TransformField.FORCE.getPreferredName(), Boolean.toString(true)); | ||
Map<String, Object> stopTransformResponse = entityAsMap(client().performRequest(stopTransformRequest)); | ||
assertThat(stopTransformResponse.get("acknowledged"), equalTo(Boolean.TRUE)); | ||
|
||
// the task is gone | ||
assertEquals(1, getNumberOfTransformTasks()); | ||
} | ||
|
||
@SuppressWarnings("unchecked") | ||
private int getNumberOfTransformTasks() throws IOException { | ||
final Request tasksRequest = new Request("GET", "/_tasks"); | ||
tasksRequest.addParameter("actions", TransformField.TASK_NAME + "*"); | ||
Map<String, Object> tasksResponse = entityAsMap(client().performRequest(tasksRequest)); | ||
|
||
Map<String, Object> nodes = (Map<String, Object>) tasksResponse.get("nodes"); | ||
if (nodes == null) { | ||
return 0; | ||
} | ||
|
||
int foundTasks = 0; | ||
for (Entry<String, Object> node : nodes.entrySet()) { | ||
Map<String, Object> nodeInfo = (Map<String, Object>) node.getValue(); | ||
Map<String, Object> tasks = (Map<String, Object>) nodeInfo.get("tasks"); | ||
foundTasks += tasks != null ? tasks.size() : 0; | ||
} | ||
|
||
return foundTasks; | ||
} | ||
|
||
private void beEvilAndDeleteTheTransformIndex() throws IOException { | ||
adminClient().performRequest(new Request("DELETE", TransformInternalIndexConstants.LATEST_INDEX_NAME)); | ||
} | ||
} |
Oops, something went wrong.