Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
66 commits
Select commit Hold shift + click to select a range
28bc7f9
Initial plumbing - need to address TODOs
joshua-adams-1 Feb 11, 2026
9427763
Creates Reindexer.lookupRemoteVersion
joshua-adams-1 Feb 13, 2026
3430f18
Refactor RemoteScrollableHitSource to use the utils class
joshua-adams-1 Feb 13, 2026
66f7deb
Clean up code
joshua-adams-1 Feb 13, 2026
a434f0d
Clean up TODOs
joshua-adams-1 Feb 13, 2026
7516540
[CI] Auto commit changes from spotless
Feb 13, 2026
1739e0f
Nits
joshua-adams-1 Feb 23, 2026
a805729
Move remote lookup into execute
joshua-adams-1 Feb 23, 2026
d5471f0
Add Tests
joshua-adams-1 Feb 23, 2026
b0c22a9
Merge branch 'main' into reindexing-plumb-pittable-hit-source
joshua-adams-1 Feb 23, 2026
6b86337
Merge conflicts
joshua-adams-1 Feb 23, 2026
61b187a
Merge branch 'reindexing-plumb-pittable-hit-source' of github.com:jos…
joshua-adams-1 Feb 23, 2026
13bdc0b
[CI] Auto commit changes from spotless
Feb 23, 2026
1dd0afc
Clean up
joshua-adams-1 Feb 23, 2026
9cf2f11
Merge branch 'reindexing-plumb-pittable-hit-source' of github.com:jos…
joshua-adams-1 Feb 23, 2026
460140c
[CI] Auto commit changes from spotless
Feb 23, 2026
5fd8ab0
Update RemoteScrollablePaginatedHitSourceTests to randomly set remote
joshua-adams-1 Feb 24, 2026
298f6fb
Merge branch 'reindexing-plumb-pittable-hit-source' of github.com:jos…
joshua-adams-1 Feb 24, 2026
6192133
Merge branch 'main' into reindexing-plumb-pittable-hit-source
joshua-adams-1 Feb 24, 2026
ec2517b
Close REST client
joshua-adams-1 Feb 24, 2026
3ba1670
[CI] Auto commit changes from spotless
Feb 24, 2026
363f2c2
Add retry logic to remote version lookup
joshua-adams-1 Feb 25, 2026
2a4e999
Add retry logic unit tests
joshua-adams-1 Feb 25, 2026
5899ba4
Merge branch 'reindexing-plumb-pittable-hit-source' of github.com:jos…
joshua-adams-1 Feb 25, 2026
04fe410
Merge branch 'main' into reindexing-plumb-pittable-hit-source
joshua-adams-1 Feb 25, 2026
8552f60
Merge main
joshua-adams-1 Feb 25, 2026
fd5aed5
Open and Close PIT for reindexing
joshua-adams-1 Feb 25, 2026
710daf6
Fix unit tests
joshua-adams-1 Feb 25, 2026
6790f2f
Wrap listener in metrics
joshua-adams-1 Feb 25, 2026
3378322
Add unit tests for RemoteReindexingUtils, RemoteRequestBuilders and
joshua-adams-1 Feb 25, 2026
a03ef53
Add ReindexerTests
joshua-adams-1 Feb 26, 2026
e58bd07
Spotless apply
joshua-adams-1 Feb 27, 2026
1067741
Merge branch 'main' into reindexing-resilience-full
joshua-adams-1 Feb 27, 2026
d1c9a09
Merge main
joshua-adams-1 Feb 27, 2026
3af6d7c
Fix tests post merge
joshua-adams-1 Feb 27, 2026
1dbc15f
Nits
joshua-adams-1 Feb 27, 2026
57ac7a1
Remove FQ imports
joshua-adams-1 Feb 27, 2026
5759987
Add metric IT
joshua-adams-1 Feb 27, 2026
aaed267
Remove TODO
joshua-adams-1 Feb 27, 2026
ed69ab6
Unused imports
joshua-adams-1 Feb 27, 2026
d56a445
[CI] Auto commit changes from spotless
Feb 27, 2026
c742468
Fix parser and remove build.gradle changes
joshua-adams-1 Mar 4, 2026
549e152
Merge branch 'reindexing-resilience-full' of github.com:joshua-adams-…
joshua-adams-1 Mar 4, 2026
82c258f
Merge branch 'main' into reindexing-resilience-full
joshua-adams-1 Mar 4, 2026
4bfdb7e
Merge branch 'main' into reindexing-resilience-full
joshua-adams-1 Mar 4, 2026
abb675a
[CI] Auto commit changes from spotless
Mar 4, 2026
437e6d1
Add assertions to openPit
joshua-adams-1 Mar 5, 2026
4e80fbe
Explicitly set allow_partial_search_results to false
joshua-adams-1 Mar 5, 2026
5130404
Apply changes to local PIT request
joshua-adams-1 Mar 5, 2026
32ed73f
Minor tweaks
joshua-adams-1 Mar 5, 2026
437e99a
Merge branch 'reindexing-resilience-full' of github.com:joshua-adams-…
joshua-adams-1 Mar 5, 2026
6cc38a9
Merge branch 'main' into reindexing-resilience-full
joshua-adams-1 Mar 5, 2026
6217e57
Fix cluster feature merge error
joshua-adams-1 Mar 5, 2026
2e181ac
Fix test comments
joshua-adams-1 Mar 5, 2026
371a786
Merge branch 'main' into reindexing-resilience-full
joshua-adams-1 Mar 5, 2026
504043d
Merge branch 'main' into reindexing-resilience-full
joshua-adams-1 Mar 5, 2026
0062697
Merge branch 'main' into reindexing-resilience-full
joshua-adams-1 Mar 10, 2026
e2b2fb8
Tidy up merge
joshua-adams-1 Mar 10, 2026
d7e3e90
Merge branch 'reindexing-resilience-full' of github.com:joshua-adams-…
joshua-adams-1 Mar 10, 2026
724866c
Fix failing integ tests
joshua-adams-1 Mar 10, 2026
730086d
Add TODO
joshua-adams-1 Mar 10, 2026
5756760
Add feature flag block to testCancelEndpointEndToEndSynchronously and…
joshua-adams-1 Mar 11, 2026
b89774d
Merge branch 'main' into reindexing-resilience-full
joshua-adams-1 Mar 11, 2026
86bf142
Merge branch 'main' into reindexing-resilience-full
joshua-adams-1 Mar 12, 2026
6222af4
Merge branch 'main' into reindexing-resilience-full
joshua-adams-1 Mar 12, 2026
cf57b30
Merge branch 'main' into reindexing-resilience-full
joshua-adams-1 Mar 12, 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
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,8 @@ public void setup() {
* We test synchronous (<code>?wait_for_completion=true</code>) invocation of the _cancel endpoint in this test.
*/
public void testCancelEndpointEndToEndSynchronously() throws Exception {
assumeFalse("scroll-based reindex uses a different code path", ReindexPlugin.REINDEX_PIT_SEARCH_ENABLED);
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These tests fail because:

  1. On snapshot builds the REINDEX_PIT_SEARCH_ENABLED feature flag is enabled
  2. We open a PIT before we slice. This is an asynchronous operation and requires waiting
  3. Then we create the worker tasks
  4. Each worker task creates a scroll

The test flow does not account for the asynchronous waiting of the PIT. I could modify the test to account for both pit and scroll functionality, but since PIT isn't complete yet, it is easier to disable these tests unless we're running with scroll. When PIT is complete, I shall make a PIT specific version of this test. I've made a note of this in https://github.com/elastic/elasticsearch-team/issues/2088 so that I don't forget.


final TaskId parentTaskId = startAsyncThrottledReindex();

final TaskInfo running = getRunningTask(parentTaskId);
Expand Down Expand Up @@ -139,6 +141,8 @@ public void testCancelEndpointEndToEndSynchronously() throws Exception {

/** Same test as above but calling _cancel asynchronously and wrapping assertions after cancellation in assertBusy. */
public void testCancelEndpointEndToEndAsynchronously() throws Exception {
assumeFalse("scroll-based reindex uses a different code path", ReindexPlugin.REINDEX_PIT_SEARCH_ENABLED);

final TaskId parentTaskId = startAsyncThrottledReindex();

final TaskInfo running = getRunningTask(parentTaskId);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,16 @@
package org.elasticsearch.index.reindex;

import org.elasticsearch.ElasticsearchStatusException;
import org.elasticsearch.action.support.IndicesOptions;
import org.elasticsearch.common.bytes.BytesArray;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.core.TimeValue;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.plugins.Plugin;
import org.elasticsearch.plugins.PluginsService;
import org.elasticsearch.reindex.BulkIndexByScrollResponseMatcher;
import org.elasticsearch.reindex.ReindexPlugin;
import org.elasticsearch.reindex.Reindexer;
import org.elasticsearch.reindex.TransportReindexAction;
import org.elasticsearch.rest.root.MainRestPlugin;
import org.elasticsearch.search.slice.SliceBuilder;
Expand Down Expand Up @@ -44,6 +47,7 @@
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertHitCount;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.greaterThanOrEqualTo;
import static org.hamcrest.Matchers.notNullValue;

@ESIntegTestCase.ClusterScope(numDataNodes = 0, numClientNodes = 0, scope = ESIntegTestCase.Scope.TEST)
public class ReindexPluginMetricsIT extends ESIntegTestCase {
Expand Down Expand Up @@ -329,6 +333,124 @@ public void testReindexMetricsWithAutoSlices() throws Exception {
});
}

/**
* Verifies that remote reindex metrics record failures when the remote version lookup fails
* (e.g. connection refused, host unreachable).
*/
public void testRemoteReindexVersionLookupFailureMetrics() throws Exception {
assumeTrue("PIT search must be enabled for remote version lookup path", ReindexPlugin.REINDEX_PIT_SEARCH_ENABLED);

final String dataNodeName = internalCluster().startNode();

// Use an invalid host so version lookup fails during connection
RemoteInfo invalidRemote = new RemoteInfo(
"http",
"invalid.invalid",
9200,
null,
new BytesArray("{\"match_all\":{}}"),
null,
null,
Map.of(),
TimeValue.timeValueMillis(100),
TimeValue.timeValueMillis(100)
);

final TestTelemetryPlugin testTelemetryPlugin = internalCluster().getInstance(PluginsService.class, dataNodeName)
.filterPlugins(TestTelemetryPlugin.class)
.findFirst()
.orElseThrow();

expectThrows(Exception.class, () -> reindex().source("source").setRemoteInfo(invalidRemote).destination("dest").get());

assertBusy(() -> {
testTelemetryPlugin.collect();
assertThat(testTelemetryPlugin.getLongHistogramMeasurement(REINDEX_TIME_HISTOGRAM).size(), equalTo(1));
List<Measurement> completions = testTelemetryPlugin.getLongCounterMeasurement(REINDEX_COMPLETION_COUNTER);
assertThat(completions.size(), equalTo(1));
assertThat(completions.getFirst().attributes().get(ATTRIBUTE_NAME_ERROR_TYPE), notNullValue());
assertThat(completions.getFirst().attributes().get(ATTRIBUTE_NAME_SOURCE), equalTo(ATTRIBUTE_VALUE_SOURCE_REMOTE));
});
}

/**
* Verifies that no reindex metrics are recorded when validation fails before the {@link Reindexer} runs
* (e.g. source index does not exist).
*/
public void testLocalReindexValidationFailureNoMetrics() {
final String dataNodeName = internalCluster().startNode();

final TestTelemetryPlugin testTelemetryPlugin = internalCluster().getInstance(PluginsService.class, dataNodeName)
.filterPlugins(TestTelemetryPlugin.class)
.findFirst()
.orElseThrow();

expectThrows(Exception.class, () -> reindex().source("non_existent_index").destination("dest").get());

testTelemetryPlugin.collect();
assertThat(testTelemetryPlugin.getLongHistogramMeasurement(REINDEX_TIME_HISTOGRAM).size(), equalTo(0));
assertThat(testTelemetryPlugin.getLongCounterMeasurement(REINDEX_COMPLETION_COUNTER).size(), equalTo(0));
}

/**
* Verifies that local reindex metrics record failures when PIT open fails (e.g. source index is closed).
*/
public void testLocalReindexPitOpenFailureMetrics() throws Exception {
assumeTrue("PIT search must be enabled for local PIT path", ReindexPlugin.REINDEX_PIT_SEARCH_ENABLED);

final String dataNodeName = internalCluster().startNode();

// Create and close the source index so PIT open fails (validation passes because index exists)
indexRandom(true, prepareIndex("source").setId("1").setSource("foo", "a"));
indicesAdmin().prepareClose("source").get();

final TestTelemetryPlugin testTelemetryPlugin = internalCluster().getInstance(PluginsService.class, dataNodeName)
.filterPlugins(TestTelemetryPlugin.class)
.findFirst()
.orElseThrow();

// Use STRICT_EXPAND_OPEN_CLOSED so validation resolves the closed index; PIT open will still fail
ReindexRequestBuilder builder = reindex().source("source").destination("dest");
builder.source().setIndicesOptions(IndicesOptions.STRICT_EXPAND_OPEN_CLOSED);
expectThrows(Exception.class, () -> builder.get());

assertBusy(() -> {
testTelemetryPlugin.collect();
assertThat(testTelemetryPlugin.getLongHistogramMeasurement(REINDEX_TIME_HISTOGRAM).size(), equalTo(1));
List<Measurement> completions = testTelemetryPlugin.getLongCounterMeasurement(REINDEX_COMPLETION_COUNTER);
assertThat(completions.size(), equalTo(1));
assertThat(completions.getFirst().attributes().get(ATTRIBUTE_NAME_ERROR_TYPE), notNullValue());
assertThat(completions.getFirst().attributes().get(ATTRIBUTE_NAME_SOURCE), equalTo(ATTRIBUTE_VALUE_SOURCE_LOCAL));
});
}

/**
* Verifies reindex metrics for a successful local reindex.
* Uses the scroll path when PIT is disabled, or the PIT path when PIT is enabled.
*/
public void testLocalReindexMetrics() throws Exception {
final String dataNodeName = internalCluster().startNode();

indexRandom(true, prepareIndex("source").setId("1").setSource("foo", "a"), prepareIndex("source").setId("2").setSource("foo", "b"));
assertHitCount(prepareSearch("source").setSize(0), 2);

final TestTelemetryPlugin testTelemetryPlugin = internalCluster().getInstance(PluginsService.class, dataNodeName)
.filterPlugins(TestTelemetryPlugin.class)
.findFirst()
.orElseThrow();

reindex().source("source").destination("dest").get();

assertBusy(() -> {
testTelemetryPlugin.collect();
assertThat(testTelemetryPlugin.getLongHistogramMeasurement(REINDEX_TIME_HISTOGRAM).size(), equalTo(1));
List<Measurement> completions = testTelemetryPlugin.getLongCounterMeasurement(REINDEX_COMPLETION_COUNTER);
assertThat(completions.size(), equalTo(1));
assertNull(completions.getFirst().attributes().get(ATTRIBUTE_NAME_ERROR_TYPE));
assertThat(completions.getFirst().attributes().get(ATTRIBUTE_NAME_SOURCE), equalTo(ATTRIBUTE_VALUE_SOURCE_LOCAL));
});
}

public void testDeleteByQueryMetrics() throws Exception {
final String dataNodeName = internalCluster().startNode();

Expand Down
Loading
Loading