-
Notifications
You must be signed in to change notification settings - Fork 25k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Browse files
Browse the repository at this point in the history
If as part of the persistent task assignment the source downsample index no longer exists, then the persistent task framework will continuously try to find an assignment and fail with IndexNotFoundException (which gets logged as a warning on elected master node). This fixes a bug in resolving the shard routing, so that if the index no longer exists any node is returned and the persistent task can fail gracefully at a later stage. The original fix via #98769 didn't get this part right. Co-authored-by: Elastic Machine <[email protected]>
- Loading branch information
1 parent
2eb9729
commit 4d62a32
Showing
3 changed files
with
140 additions
and
1 deletion.
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
pr: 106247 | ||
summary: Fix a downsample persistent task assignment bug | ||
area: Downsampling | ||
type: bug | ||
issues: [] |
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
125 changes: 125 additions & 0 deletions
125
...t/java/org/elasticsearch/xpack/downsample/DownsampleShardPersistentTaskExecutorTests.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,125 @@ | ||
/* | ||
* 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.downsample; | ||
|
||
import org.elasticsearch.action.downsample.DownsampleConfig; | ||
import org.elasticsearch.client.internal.Client; | ||
import org.elasticsearch.cluster.ClusterState; | ||
import org.elasticsearch.cluster.metadata.DataStreamTestHelper; | ||
import org.elasticsearch.cluster.node.DiscoveryNode; | ||
import org.elasticsearch.cluster.node.DiscoveryNodeRole; | ||
import org.elasticsearch.cluster.node.DiscoveryNodeUtils; | ||
import org.elasticsearch.cluster.node.DiscoveryNodes; | ||
import org.elasticsearch.cluster.routing.IndexRoutingTable; | ||
import org.elasticsearch.cluster.routing.RoutingTable; | ||
import org.elasticsearch.common.Strings; | ||
import org.elasticsearch.common.UUIDs; | ||
import org.elasticsearch.core.Tuple; | ||
import org.elasticsearch.index.Index; | ||
import org.elasticsearch.index.shard.ShardId; | ||
import org.elasticsearch.search.aggregations.bucket.histogram.DateHistogramInterval; | ||
import org.elasticsearch.test.ESTestCase; | ||
import org.elasticsearch.xpack.core.downsample.DownsampleShardTask; | ||
import org.junit.Before; | ||
|
||
import java.time.Instant; | ||
import java.time.temporal.ChronoUnit; | ||
import java.util.List; | ||
import java.util.Map; | ||
import java.util.Set; | ||
import java.util.concurrent.Executor; | ||
|
||
import static org.elasticsearch.cluster.routing.ShardRoutingState.STARTED; | ||
import static org.elasticsearch.cluster.routing.TestShardRouting.shardRoutingBuilder; | ||
import static org.hamcrest.Matchers.equalTo; | ||
import static org.mockito.Mockito.mock; | ||
|
||
public class DownsampleShardPersistentTaskExecutorTests extends ESTestCase { | ||
|
||
private ClusterState initialClusterState; | ||
private DownsampleShardPersistentTaskExecutor executor; | ||
|
||
@Before | ||
public void setup() { | ||
Instant now = Instant.now().truncatedTo(ChronoUnit.MILLIS); | ||
Instant start = now.minus(2, ChronoUnit.HOURS); | ||
Instant end = now.plus(40, ChronoUnit.MINUTES); | ||
initialClusterState = DataStreamTestHelper.getClusterStateWithDataStream("metrics-app1", List.of(new Tuple<>(start, end))); | ||
executor = new DownsampleShardPersistentTaskExecutor(mock(Client.class), DownsampleShardTask.TASK_NAME, mock(Executor.class)); | ||
} | ||
|
||
public void testGetAssignment() { | ||
var backingIndex = initialClusterState.metadata().dataStreams().get("metrics-app1").getWriteIndex(); | ||
var node = newNode(); | ||
var shardId = new ShardId(backingIndex, 0); | ||
var clusterState = ClusterState.builder(initialClusterState) | ||
.nodes(new DiscoveryNodes.Builder().add(node).build()) | ||
.routingTable( | ||
RoutingTable.builder() | ||
.add( | ||
IndexRoutingTable.builder(backingIndex) | ||
.addShard(shardRoutingBuilder(shardId, node.getId(), true, STARTED).withRecoverySource(null).build()) | ||
) | ||
) | ||
.build(); | ||
|
||
var params = new DownsampleShardTaskParams( | ||
new DownsampleConfig(new DateHistogramInterval("1h")), | ||
shardId.getIndexName(), | ||
1, | ||
1, | ||
shardId, | ||
Strings.EMPTY_ARRAY, | ||
Strings.EMPTY_ARRAY, | ||
Strings.EMPTY_ARRAY | ||
); | ||
var result = executor.getAssignment(params, Set.of(node), clusterState); | ||
assertThat(result.getExecutorNode(), equalTo(node.getId())); | ||
} | ||
|
||
public void testGetAssignmentMissingIndex() { | ||
var backingIndex = initialClusterState.metadata().dataStreams().get("metrics-app1").getWriteIndex(); | ||
var node = newNode(); | ||
var shardId = new ShardId(backingIndex, 0); | ||
var clusterState = ClusterState.builder(initialClusterState) | ||
.nodes(new DiscoveryNodes.Builder().add(node).build()) | ||
.routingTable( | ||
RoutingTable.builder() | ||
.add( | ||
IndexRoutingTable.builder(backingIndex) | ||
.addShard(shardRoutingBuilder(shardId, node.getId(), true, STARTED).withRecoverySource(null).build()) | ||
) | ||
) | ||
.build(); | ||
|
||
var missingShardId = new ShardId(new Index("another_index", "uid"), 0); | ||
var params = new DownsampleShardTaskParams( | ||
new DownsampleConfig(new DateHistogramInterval("1h")), | ||
missingShardId.getIndexName(), | ||
1, | ||
1, | ||
missingShardId, | ||
Strings.EMPTY_ARRAY, | ||
Strings.EMPTY_ARRAY, | ||
Strings.EMPTY_ARRAY | ||
); | ||
var result = executor.getAssignment(params, Set.of(node), clusterState); | ||
assertThat(result.getExecutorNode(), equalTo(node.getId())); | ||
assertThat(result.getExplanation(), equalTo("a node to fail and stop this persistent task")); | ||
} | ||
|
||
private static DiscoveryNode newNode() { | ||
return DiscoveryNodeUtils.create( | ||
"node_" + UUIDs.randomBase64UUID(random()), | ||
buildNewFakeTransportAddress(), | ||
Map.of(), | ||
DiscoveryNodeRole.roles() | ||
); | ||
} | ||
|
||
} |