Skip to content

Commit 490b47d

Browse files
committed
#1327 QueryBatcher now stops when query fails
Addresses DEVEXP-147 (internal bug).
1 parent 1169eb9 commit 490b47d

File tree

2 files changed

+64
-14
lines changed

2 files changed

+64
-14
lines changed

marklogic-client-api/src/main/java/com/marklogic/client/datamovement/impl/QueryBatcherImpl.java

Lines changed: 16 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -228,9 +228,9 @@ private void retry(QueryEvent queryEvent, boolean callFailListeners) {
228228
runnable.run();
229229
}
230230
/*
231-
* Accepts a QueryBatch which was successfully retrieved from the server and a
232-
* QueryBatchListener which was failed to apply and retry that listener on the batch.
233-
*
231+
* Accepts a QueryBatch which was successfully retrieved from the server and a
232+
* QueryBatchListener which was failed to apply and retry that listener on the batch.
233+
*
234234
*/
235235
@Override
236236
public void retryListener(QueryBatch batch, QueryBatchListener queryBatchListener) {
@@ -675,23 +675,22 @@ private class QueryTask implements Runnable {
675675
private boolean callFailListeners;
676676
private String afterUri;
677677
private String nextAfterUri;
678-
boolean isQueryBatch;
679678
private QueryBatchImpl batch;
680679
private int totalProcessedCount = 0;
681-
private boolean isLastBatch;
682-
private int lastBatchNum;
683680

684681
QueryTask(DataMovementManager moveMgr, QueryBatcherImpl batcher, Forest forest,
685682
String queryMethod, SearchQueryDefinition query, Boolean filtered, long forestBatchNum, long start, QueryBatchImpl batch
686683
) {
687684
this(moveMgr, batcher, forest, queryMethod, query, filtered, forestBatchNum, start, batch, null, -1, true);
688685
}
686+
689687
QueryTask(DataMovementManager moveMgr, QueryBatcherImpl batcher, Forest forest,
690688
String queryMethod, SearchQueryDefinition query, Boolean filtered, long forestBatchNum, long start, QueryBatchImpl batch, String afterUri
691689
) {
692690
this(moveMgr, batcher, forest, queryMethod, query, filtered, forestBatchNum, start, batch, afterUri,
693691
-1, true);
694692
}
693+
695694
QueryTask(DataMovementManager moveMgr, QueryBatcherImpl batcher, Forest forest,
696695
String queryMethod, SearchQueryDefinition query, Boolean filtered, long forestBatchNum, long start,
697696
QueryBatchImpl batch, String afterUri, long retryBatchNumber, boolean callFailListeners
@@ -704,7 +703,6 @@ private class QueryTask implements Runnable {
704703
this.filtered = filtered;
705704
this.forestBatchNum = forestBatchNum;
706705
this.start = start;
707-
this.isQueryBatch = isQueryBatch;
708706
this.retryBatchNumber = retryBatchNumber;
709707
this.callFailListeners = callFailListeners;
710708
this.batch = batch;
@@ -745,12 +743,8 @@ public void run() {
745743
if (consistentSnapshot == true && serverTimestamp.get() > -1) {
746744
handle.setPointInTimeQueryTimestamp(serverTimestamp.get());
747745
}
748-
// this try-with-resources block will call results.close() once the block is done
749-
// here we call the /v1/internal/uris endpoint to get the text/uri-list of documents
750-
// matching this structured or string query
746+
751747
try (UrisHandle results = queryMgr.uris(queryMethod, query, filtered, handle, start, afterUri, forest.getForestName())) {
752-
// if we're doing consistentSnapshot and this is the first result set, let's capture the
753-
// serverTimestamp so we can use it for all future queries
754748
if (consistentSnapshot == true && serverTimestamp.get() == -1) {
755749
if (serverTimestamp.compareAndSet(-1, results.getServerTimestamp())) {
756750
logger.info("Consistent snapshot timestamp=[{}]", serverTimestamp);
@@ -785,7 +779,15 @@ public void run() {
785779
isDone.set(true);
786780
shutdownIfAllForestsAreDone();
787781
return;
788-
}
782+
} catch (Throwable t) {
783+
// The above catch on a ResourceNotFoundException seems to be an expected error that doesn't need to be
784+
// logged. But if the query fails for any other reason, such as an invalid index, the error should be
785+
// logged and the job stopped.
786+
logger.error("Query for URIs failed, stopping job; cause: " + t.getMessage(), t);
787+
isDone.set(true);
788+
shutdownIfAllForestsAreDone();
789+
return;
790+
}
789791

790792
batch = batch
791793
.withItems(uris.get(0).toArray(new String[uris.get(0).size()]))
@@ -959,7 +961,7 @@ public void run() {
959961
final List<String> uris = uriQueue;
960962
final boolean finalLastBatch = lastBatch;
961963
final long results = resultsSoFar.addAndGet(uris.size());
962-
if(maxUris <= results)
964+
if(maxUris <= results)
963965
lastBatch = true;
964966
uriQueue = new ArrayList<>(getBatchSize());
965967
Runnable processBatch = new Runnable() {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
package com.marklogic.client.test.datamovement;
2+
3+
import com.marklogic.client.datamovement.DataMovementManager;
4+
import com.marklogic.client.datamovement.QueryBatcher;
5+
import com.marklogic.client.query.StructuredQueryBuilder;
6+
import com.marklogic.client.query.StructuredQueryDefinition;
7+
import com.marklogic.client.test.Common;
8+
import org.junit.jupiter.api.Test;
9+
10+
import java.util.concurrent.atomic.AtomicBoolean;
11+
12+
import static org.junit.jupiter.api.Assertions.assertFalse;
13+
14+
public class QueryBatcherInitialQueryFailsTest {
15+
16+
@Test
17+
void jobStopsWhenQueryIsInvalid() {
18+
Common.connect();
19+
20+
StructuredQueryBuilder queryBuilder = Common.client.newQueryManager().newStructuredQueryBuilder();
21+
StructuredQueryDefinition invalidQuery = queryBuilder.range(
22+
queryBuilder.pathIndex("doesnt-work"),
23+
"xs:date", StructuredQueryBuilder.Operator.GT, "2007-01-01"
24+
);
25+
26+
AtomicBoolean successListenerInvoked = new AtomicBoolean(false);
27+
AtomicBoolean failureListenerInvoked = new AtomicBoolean(false);
28+
29+
DataMovementManager dataMovementManager = Common.client.newDataMovementManager();
30+
QueryBatcher queryBatcher = dataMovementManager.newQueryBatcher(invalidQuery)
31+
.onUrisReady(batch -> successListenerInvoked.set(true))
32+
.onQueryFailure(failure -> failureListenerInvoked.set(true));
33+
34+
dataMovementManager.startJob(queryBatcher);
35+
queryBatcher.awaitCompletion();
36+
dataMovementManager.stopJob(queryBatcher);
37+
38+
assertFalse(successListenerInvoked.get(),
39+
"The success listener should not have been invoked since the initial query was failed; additionally, " +
40+
"getting to this point in the test verifies that the job stopped successfully, which prior to this " +
41+
"test being written would not occur due to a bug");
42+
43+
assertFalse(failureListenerInvoked.get(),
44+
"The failure listener should not have been invoked either; see QueryBatcherFailureTest for an explanation " +
45+
"as to what a failure listener actually captures (it does not capture failures from an invalid query)");
46+
}
47+
48+
}

0 commit comments

Comments
 (0)