This is an automated email from the ASF dual-hosted git repository.
epugh pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/solr-mcp.git
The following commit(s) were added to refs/heads/main by this push:
new 48953297 perf(indexing): one request per JSON/markdown call; retry per
document only on a 400 (#233)
48953297 is described below
commit 48953297a45d7dc5a83f5cad99a91ace8ffa550c
Author: Aditya Parikh <[email protected]>
AuthorDate: Tue Oct 6 14:50:30 2026 -0400
perf(indexing): one request per JSON/markdown call; retry per document only
on a 400 (#233)
* perf(indexing): cut redundant Solr round trips in indexDocuments
indexDocuments() retried every document individually on ANY batch
failure (SolrServerException/IOException/RuntimeException), swallowing
the cause and costing up to N+2 round trips per batch on a missing
collection, auth failure, 5xx, or Solr being down -- ending as
"Successfully indexed 0 of N" instead of reporting the real error.
Per-document fallback now only fires for a Solr 400 (bad documents);
everything else propagates immediately with the root cause intact.
JSON/markdown indexing also issued a separate solrClient.commit() call
after the adds. The last batch now carries add + commit on a single
UpdateRequest (same soft-commit semantics: waitSearcher=true,
searchable on return), matching how CSV/XML already ride the commit on
their forwarded request. Markdown (always one document) and JSON up to
the batch size go from two round trips to one. A batch that falls back
to per-document retry still commits explicitly, since its embedded
commit never ran.
Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
Signed-off-by: Aditya Parikh <[email protected]>
* refactor(indexing): send JSON and markdown documents in one request
Replace the client-side 1000-document batching with one UpdateRequest
carrying the documents and the soft commit, as CSV and XML already
send their whole payload in one request. The documents arrive in a
single MCP call and are already in memory, so batching bought nothing
and needed last-batch bookkeeping to place the commit.
A 400 still falls back to per-document adds followed by a commit.
The per-call field-name memo in JsonDocumentCreator is reverted: it
saved CPU only, not Solr round trips.
Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
Signed-off-by: Aditya Parikh <[email protected]>
---------
Signed-off-by: Aditya Parikh <[email protected]>
Co-authored-by: Claude Opus 5.5 (1M context) <[email protected]>
---
.../solr/mcp/server/indexing/IndexingService.java | 142 ++++++-------------
.../mcp/server/indexing/IndexingServiceTest.java | 152 ++++++++++-----------
2 files changed, 114 insertions(+), 180 deletions(-)
diff --git
a/src/main/java/org/apache/solr/mcp/server/indexing/IndexingService.java
b/src/main/java/org/apache/solr/mcp/server/indexing/IndexingService.java
index e5ae85f2..2d6fdc20 100644
--- a/src/main/java/org/apache/solr/mcp/server/indexing/IndexingService.java
+++ b/src/main/java/org/apache/solr/mcp/server/indexing/IndexingService.java
@@ -27,8 +27,10 @@ import org.apache.solr.client.solrj.SolrClient;
import org.apache.solr.client.solrj.SolrServerException;
import org.apache.solr.client.solrj.request.AbstractUpdateRequest;
import org.apache.solr.client.solrj.request.ContentStreamUpdateRequest;
+import org.apache.solr.client.solrj.request.UpdateRequest;
import org.apache.solr.client.solrj.response.UpdateResponse;
import org.apache.solr.client.solrj.util.ClientUtils;
+import org.apache.solr.common.SolrException;
import org.apache.solr.common.SolrInputDocument;
import org.apache.solr.common.util.ContentStreamBase;
import
org.apache.solr.mcp.server.indexing.documentcreator.IndexingDocumentCreator;
@@ -50,9 +52,9 @@ import org.springframework.stereotype.Service;
* <p>
* This service handles the conversion of JSON, CSV, XML, and markdown
documents
* into Solr-compatible format and manages the indexing process with robust
- * error handling and batch processing capabilities. It employs a schema-less
- * approach where Solr automatically detects field types, eliminating the need
- * for predefined schema configuration.
+ * error handling. It employs a schema-less approach where Solr automatically
+ * detects field types, eliminating the need for predefined schema
+ * configuration.
*
* <p>
* <strong>Core Features:</strong>
@@ -68,10 +70,8 @@ import org.springframework.stereotype.Service;
* forwarded to Solr's XML update handler
* <li><strong>Markdown Processing</strong>: Support for markdown documents
with
* front matter, title, and heading extraction
- * <li><strong>Batch Processing</strong>: Efficient bulk indexing with
- * configurable batch sizes
- * <li><strong>Error Resilience</strong>: Individual document fallback when
- * batch operations fail
+ * <li><strong>Error Resilience</strong>: Individual document fallback when
Solr
+ * rejects a document
* <li><strong>Field Names</strong>: Used as given in every format; nested JSON
* objects are flattened with underscores
* </ul>
@@ -93,13 +93,12 @@ import org.springframework.stereotype.Service;
* arrays by converting them to multi-valued fields that Solr natively
supports.
*
* <p>
- * <strong>Batch Processing Strategy:</strong>
+ * <strong>Error Recovery:</strong>
*
* <p>
- * Uses configurable batch sizes (default 1000 documents) for optimal
- * performance. If a batch fails, the service automatically retries by indexing
- * documents individually to identify and skip problematic documents while
- * preserving valid ones.
+ * JSON and markdown documents are sent in one update request. If Solr rejects
+ * it because of a bad document, the service retries the documents individually
+ * to skip the problematic ones while preserving valid ones.
*
* <p>
* <strong>Example Usage:</strong>
@@ -124,8 +123,6 @@ public class IndexingService {
private static final Logger logger =
LoggerFactory.getLogger(IndexingService.class);
- private static final int DEFAULT_BATCH_SIZE = 1000;
-
/** SolrJ client for communicating with Solr server */
private final SolrClient solrClient;
@@ -179,7 +176,7 @@ public class IndexingService {
* <ol>
* <li>Parse JSON string into structured documents
* <li>Convert to schema-less SolrInputDocument objects
- * <li>Execute batch indexing with error handling
+ * <li>Index them in one request, with error handling
* <li>Commit changes to make documents searchable
* </ol>
*
@@ -428,107 +425,52 @@ public class IndexingService {
}
/**
- * Indexes a list of SolrInputDocument objects into a Solr collection
using
- * batch processing.
- *
- * <p>
- * This method implements a robust batch indexing strategy that
optimizes
- * performance while providing resilience against individual document
failures.
- * It processes documents in configurable batches and includes fallback
- * mechanisms for error recovery.
- *
- * <p>
- * <strong>Batch Processing Strategy:</strong>
- *
- * <ul>
- * <li><strong>Batch Size</strong>: Configurable (default 1000) for
optimal
- * performance
- * <li><strong>Error Recovery</strong>: Individual document retry on
batch
- * failure
- * <li><strong>Success Tracking</strong>: Accurate count of
successfully indexed
- * documents
- * <li><strong>Commit Strategy</strong>: Single soft commit after all
batches
- * for consistency
- * </ul>
- *
- * <p>
- * <strong>Error Handling Workflow:</strong>
- *
- * <ol>
- * <li>Attempt batch indexing for optimal performance
- * <li>On batch failure, retry each document individually
- * <li>Track successful vs failed document counts
- * <li>Continue processing remaining batches despite failures
- * <li>Commit all successful changes at the end
- * </ol>
- *
- * <p>
- * <strong>Performance Considerations:</strong>
+ * Indexes documents into a Solr collection in one update request that
also
+ * carries the soft commit, as {@link #forward} does for CSV and XML,
so the
+ * documents are searchable when this returns.
*
* <p>
- * Batch processing significantly improves indexing performance
compared to
- * individual document operations. The fallback to individual
processing ensures
- * maximum document ingestion even when some documents have issues.
- *
- * <p>
- * <strong>Transaction Behavior:</strong>
- *
- * <p>
- * The method soft-commits after all batches are processed, making
indexed
- * documents immediately searchable. This ensures atomicity at the
operation
- * level while maintaining performance through batching.
+ * If Solr rejects the request with a 400 (a document with an unknown
field or a
+ * value of the wrong type), the documents are retried one at a time so
the
+ * valid ones are still indexed, then committed. Any other failure
(unknown
+ * collection, auth, 5xx, Solr unreachable) would fail every retry the
same way,
+ * so it propagates unchanged.
*
* @param collection
* the name of the Solr collection to index into
* @param documents
- * list of SolrInputDocument objects to index
+ * the documents to index
* @return the number of documents successfully indexed
* @throws SolrServerException
- * if there are critical errors in Solr communication
+ * if Solr cannot be reached or the commit fails
* @throws IOException
- * if there are critical errors in commit operations
- * @see SolrInputDocument
- * @see SolrClient#add(String, java.util.Collection)
- * @see SolrClient#commit(String, boolean, boolean, boolean)
+ * if there are I/O errors during communication
*/
public int indexDocuments(String collection, List<SolrInputDocument>
documents)
throws SolrServerException, IOException {
- int successCount = 0;
- final int batchSize = DEFAULT_BATCH_SIZE;
-
- for (int i = 0; i < documents.size(); i += batchSize) {
- final int endIndex = Math.min(i + batchSize,
documents.size());
- final List<SolrInputDocument> batch =
documents.subList(i, endIndex);
-
- try {
- solrClient.add(collection, batch);
- successCount += batch.size();
- } catch (SolrServerException | IOException |
RuntimeException e) {
- logger.warn("Batch indexing failed, retrying
individually", e);
- // Try indexing documents individually to
identify problematic ones
- for (SolrInputDocument doc : batch) {
- try {
- solrClient.add(collection, doc);
- successCount++;
- } catch (SolrServerException |
IOException | RuntimeException e2) {
- logger.debug("Failed to index
individual document", e2);
- // Document failed to index -
this is expected behavior for problematic
- // documents
- // We continue processing the
rest of the batch
- }
- }
+ UpdateRequest request = new UpdateRequest();
+ request.add(documents);
+ request.setAction(AbstractUpdateRequest.ACTION.COMMIT, false,
true, true);
+ try {
+ request.process(solrClient, collection);
+ return documents.size();
+ } catch (SolrException e) {
+ if (e.code() !=
SolrException.ErrorCode.BAD_REQUEST.code) {
+ throw e;
}
+ logger.warn("Solr rejected the batch, retrying
documents individually", e);
}
- try {
- // waitFlush=false, waitSearcher=true, softCommit=true:
the documents are
- // searchable when this method returns, while the hard
commit (segment fsync)
- // is left to Solr's autoCommit, so many small calls do
not each force one.
- solrClient.commit(collection, false, true, true);
- } catch (SolrServerException | IOException e) {
- logger.error("Failed to commit after indexing to
collection: {}", collection, e);
- throw e;
+ int successCount = 0;
+ for (SolrInputDocument doc : documents) {
+ try {
+ solrClient.add(collection, doc);
+ successCount++;
+ } catch (SolrException e) {
+ logger.debug("Failed to index individual
document", e);
+ }
}
+ solrClient.commit(collection, false, true, true);
return successCount;
}
diff --git
a/src/test/java/org/apache/solr/mcp/server/indexing/IndexingServiceTest.java
b/src/test/java/org/apache/solr/mcp/server/indexing/IndexingServiceTest.java
index cb42cdd8..3a9db4a8 100644
--- a/src/test/java/org/apache/solr/mcp/server/indexing/IndexingServiceTest.java
+++ b/src/test/java/org/apache/solr/mcp/server/indexing/IndexingServiceTest.java
@@ -26,9 +26,11 @@ import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
+import org.apache.solr.client.solrj.RemoteSolrException;
import org.apache.solr.client.solrj.SolrClient;
import org.apache.solr.client.solrj.SolrServerException;
import org.apache.solr.client.solrj.request.ContentStreamUpdateRequest;
+import org.apache.solr.client.solrj.request.UpdateRequest;
import org.apache.solr.common.SolrInputDocument;
import org.apache.solr.common.util.NamedList;
import
org.apache.solr.mcp.server.indexing.documentcreator.DocumentProcessingException;
@@ -71,14 +73,19 @@ class IndexingServiceTest {
List<Map<String, Object>> json = List.of(Map.of("id", "1",
"title", "Test"));
List<SolrInputDocument> mockDocs = createMockDocuments(1);
when(indexingDocumentCreator.createSchemalessDocumentsFromJson(json)).thenReturn(mockDocs);
- when(solrClient.add(eq("test_collection"),
any(Collection.class))).thenReturn(null);
- when(solrClient.commit("test_collection", false, true,
true)).thenReturn(null);
+ when(solrClient.request(any(UpdateRequest.class),
eq("test_collection"))).thenReturn(new NamedList<>());
indexingService.indexJsonDocuments("test_collection", json);
verify(indexingDocumentCreator).createSchemalessDocumentsFromJson(json);
- verify(solrClient).add(eq("test_collection"),
any(Collection.class));
- verify(solrClient).commit("test_collection", false, true, true);
+ // the add and the commit ride on one request
+ ArgumentCaptor<UpdateRequest> captor =
ArgumentCaptor.forClass(UpdateRequest.class);
+ verify(solrClient).request(captor.capture(),
eq("test_collection"));
+ assertEquals(1, captor.getValue().getDocuments().size());
+ assertEquals("true",
captor.getValue().getParams().get("commit"));
+ assertEquals("true",
captor.getValue().getParams().get("softCommit"));
+ verify(solrClient, never()).add(anyString(),
any(Collection.class));
+ verify(solrClient, never()).commit(anyString(), anyBoolean(),
anyBoolean(), anyBoolean());
}
@Test
@@ -97,119 +104,109 @@ class IndexingServiceTest {
@Test
void indexDocuments_WithSmallBatch_ShouldIndexSuccessfully() throws
Exception {
List<SolrInputDocument> docs = createMockDocuments(5);
- when(solrClient.add(eq("test_collection"),
any(Collection.class))).thenReturn(null);
- when(solrClient.commit("test_collection", false, true,
true)).thenReturn(null);
+ when(solrClient.request(any(UpdateRequest.class),
eq("test_collection"))).thenReturn(new NamedList<>());
int result = indexingService.indexDocuments("test_collection",
docs);
assertEquals(5, result);
- verify(solrClient).add(eq("test_collection"),
any(Collection.class));
- verify(solrClient).commit("test_collection", false, true, true);
+ ArgumentCaptor<UpdateRequest> captor =
ArgumentCaptor.forClass(UpdateRequest.class);
+ verify(solrClient).request(captor.capture(),
eq("test_collection"));
+ assertEquals(5, captor.getValue().getDocuments().size());
+ assertEquals("true",
captor.getValue().getParams().get("commit"));
+ verify(solrClient, never()).add(anyString(),
any(Collection.class));
+ verify(solrClient, never()).commit(anyString(), anyBoolean(),
anyBoolean(), anyBoolean());
}
@Test
- void indexDocuments_WithLargeBatch_ShouldProcessInBatches() throws
Exception {
+ void indexDocuments_WithManyDocuments_SendsOneRequest() throws
Exception {
List<SolrInputDocument> docs = createMockDocuments(2500);
- when(solrClient.add(eq("test_collection"),
any(Collection.class))).thenReturn(null);
- when(solrClient.commit(eq("test_collection"), eq(false),
eq(true), eq(true))).thenReturn(null);
+ when(solrClient.request(any(UpdateRequest.class),
eq("test_collection"))).thenReturn(new NamedList<>());
int result = indexingService.indexDocuments("test_collection",
docs);
assertEquals(2500, result);
- verify(solrClient, times(3)).add(eq("test_collection"),
any(Collection.class));
- verify(solrClient).commit("test_collection", false, true, true);
+ ArgumentCaptor<UpdateRequest> captor =
ArgumentCaptor.forClass(UpdateRequest.class);
+ verify(solrClient).request(captor.capture(),
eq("test_collection"));
+ assertEquals(2500, captor.getValue().getDocuments().size());
+ verify(solrClient, never()).add(anyString(),
any(Collection.class));
}
-
@Test
- void indexDocuments_WhenBatchFails_ShouldRetryIndividually() throws
Exception {
+ void indexDocuments_WhenSolrRejectsTheRequest_ShouldRetryIndividually()
throws Exception {
List<SolrInputDocument> docs = createMockDocuments(3);
-
- when(solrClient.add(eq("test_collection"),
any(List.class))).thenThrow(new SolrServerException("Batch error"));
-
+ when(solrClient.request(any(UpdateRequest.class),
eq("test_collection")))
+ .thenThrow(new
RemoteSolrException("http://localhost:8983/solr", 400, "Batch error", null));
when(solrClient.add(eq("test_collection"),
any(SolrInputDocument.class))).thenReturn(null);
- when(solrClient.commit("test_collection", false, true,
true)).thenReturn(null);
int result = indexingService.indexDocuments("test_collection",
docs);
assertEquals(3, result);
- verify(solrClient).add(eq("test_collection"),
any(Collection.class));
verify(solrClient, times(3)).add(eq("test_collection"),
any(SolrInputDocument.class));
+ // the rejected request's commit never ran
verify(solrClient).commit("test_collection", false, true, true);
}
-
@Test
void
indexDocuments_WhenSomeIndividualDocumentsFail_ShouldIndexSuccessfulOnes()
throws Exception {
List<SolrInputDocument> docs = createMockDocuments(3);
-
- when(solrClient.add(eq("test_collection"),
any(List.class))).thenThrow(new SolrServerException("Batch error"));
-
- when(solrClient.add(eq("test_collection"),
any(SolrInputDocument.class))).thenReturn(null)
- .thenThrow(new SolrServerException("Document
error")).thenReturn(null);
-
- when(solrClient.commit("test_collection", false, true,
true)).thenReturn(null);
+ RemoteSolrException badRequest = new
RemoteSolrException("http://localhost:8983/solr", 400, "Bad doc", null);
+ when(solrClient.request(any(UpdateRequest.class),
eq("test_collection"))).thenThrow(badRequest);
+ when(solrClient.add(eq("test_collection"),
any(SolrInputDocument.class))).thenReturn(null).thenThrow(badRequest)
+ .thenReturn(null);
int result = indexingService.indexDocuments("test_collection",
docs);
assertEquals(2, result);
- verify(solrClient).add(eq("test_collection"),
any(Collection.class));
verify(solrClient, times(3)).add(eq("test_collection"),
any(SolrInputDocument.class));
verify(solrClient).commit("test_collection", false, true, true);
}
-
- @Test
- void indexDocuments_WithEmptyList_ShouldStillCommit() throws Exception {
- List<SolrInputDocument> emptyDocs = new ArrayList<>();
- when(solrClient.commit("test_collection", false, true,
true)).thenReturn(null);
-
- int result = indexingService.indexDocuments("test_collection",
emptyDocs);
-
- assertEquals(0, result);
- verify(solrClient, never()).add(anyString(), any(List.class));
- verify(solrClient).commit("test_collection", false, true, true);
- }
-
@Test
- void indexDocuments_WhenCommitFails_ShouldPropagateException() throws
Exception {
+ void indexDocuments_WhenTheRequestFails_ShouldPropagateException()
throws Exception {
List<SolrInputDocument> docs = createMockDocuments(2);
- when(solrClient.add(eq("test_collection"),
any(Collection.class))).thenReturn(null);
- when(solrClient.commit("test_collection", false, true,
true)).thenThrow(new IOException("Commit failed"));
+ when(solrClient.request(any(UpdateRequest.class),
eq("test_collection")))
+ .thenThrow(new IOException("Commit failed"));
assertThrows(IOException.class, () -> {
indexingService.indexDocuments("test_collection", docs);
});
- verify(solrClient).add(eq("test_collection"),
any(Collection.class));
- verify(solrClient).commit("test_collection", false, true, true);
+ verify(solrClient).request(any(UpdateRequest.class),
eq("test_collection"));
+ // not a Solr 400: no per-document fallback
+ verify(solrClient, never()).add(anyString(),
any(SolrInputDocument.class));
+ verify(solrClient, never()).commit(anyString(), anyBoolean(),
anyBoolean(), anyBoolean());
}
@Test
void
indexDocuments_SoftCommitsSoDocumentsAreSearchableWithoutForcingAnFsync()
throws Exception {
List<SolrInputDocument> docs = createMockDocuments(2);
- when(solrClient.add(eq("test_collection"),
any(Collection.class))).thenReturn(null);
+ when(solrClient.request(any(UpdateRequest.class),
eq("test_collection"))).thenReturn(new NamedList<>());
indexingService.indexDocuments("test_collection", docs);
- // waitFlush=false, waitSearcher=true, softCommit=true.
waitSearcher is what
- // keeps the documents searchable the moment the tool returns;
softCommit is
- // what avoids an fsync per call. Measured against Solr: 8.6 ms
versus 18.9 ms
- // for a hard commit, and a p90 of 10.7 ms versus 41.3 ms.
- verify(solrClient).commit("test_collection", false, true, true);
+ // waitFlush=false, waitSearcher=true, softCommit=true, on the
add request.
+ // waitSearcher is what keeps the documents searchable the
moment the tool
+ // returns; softCommit is what avoids an fsync per call.
Measured against
+ // Solr: 8.6 ms versus 18.9 ms for a hard commit, and a p90 of
10.7 ms versus
+ // 41.3 ms.
+ ArgumentCaptor<UpdateRequest> captor =
ArgumentCaptor.forClass(UpdateRequest.class);
+ verify(solrClient).request(captor.capture(),
eq("test_collection"));
+ assertEquals("true",
captor.getValue().getParams().get("commit"));
+ assertEquals("true",
captor.getValue().getParams().get("softCommit"));
+ assertEquals("true",
captor.getValue().getParams().get("waitSearcher"));
+ verify(solrClient, never()).commit(anyString(), anyBoolean(),
anyBoolean(), anyBoolean());
verify(solrClient, never()).commit(anyString());
}
@Test
- void indexDocuments_ShouldBatchCorrectly() throws Exception {
- List<SolrInputDocument> docs = createMockDocuments(1000);
- when(solrClient.add(eq("test_collection"),
any(Collection.class))).thenReturn(null);
- when(solrClient.commit("test_collection", false, true,
true)).thenReturn(null);
+ void
indexDocuments_WhenCollectionIsMissing_ShouldPropagateWithoutRetrying() throws
Exception {
+ List<SolrInputDocument> docs = createMockDocuments(3);
- int result = indexingService.indexDocuments("test_collection",
docs);
+ when(solrClient.request(any(UpdateRequest.class),
eq("test_collection")))
+ .thenThrow(new
RemoteSolrException("http://localhost:8983/solr", 404, "Collection not found",
null));
- assertEquals(1000, result);
+ assertThrows(RemoteSolrException.class, () ->
indexingService.indexDocuments("test_collection", docs));
- ArgumentCaptor<Collection<SolrInputDocument>> captor =
ArgumentCaptor.forClass(Collection.class);
- verify(solrClient).add(eq("test_collection"), captor.capture());
- assertEquals(1000, captor.getValue().size());
- verify(solrClient).commit("test_collection", false, true, true);
+ verify(solrClient, times(1)).request(any(UpdateRequest.class),
eq("test_collection"));
+ verify(solrClient, never()).add(anyString(),
any(SolrInputDocument.class));
+ verify(solrClient, never()).add(anyString(),
any(Collection.class));
+ verify(solrClient, never()).commit(anyString(), anyBoolean(),
anyBoolean(), anyBoolean());
}
@Test
@@ -217,16 +214,15 @@ class IndexingServiceTest {
List<Map<String, Object>> json = List.of(Map.of("id", "1"));
List<SolrInputDocument> mockDocs = createMockDocuments(1);
when(indexingDocumentCreator.createSchemalessDocumentsFromJson(json)).thenReturn(mockDocs);
- when(solrClient.add(eq("test_collection"), any(List.class)))
- .thenThrow(new SolrServerException("Solr
connection error"));
- when(solrClient.add(eq("test_collection"),
any(SolrInputDocument.class)))
+ // Solr unreachable: propagate rather than retry and report "0
of 1"
+ when(solrClient.request(any(UpdateRequest.class),
eq("test_collection")))
.thenThrow(new SolrServerException("Solr
connection error"));
- when(solrClient.commit("test_collection", false, true,
true)).thenReturn(null);
- indexingService.indexJsonDocuments("test_collection", json);
+ assertThrows(SolrServerException.class, () ->
indexingService.indexJsonDocuments("test_collection", json));
- verify(solrClient).add(eq("test_collection"), any(List.class));
- verify(solrClient).add(eq("test_collection"),
any(SolrInputDocument.class));
+ verify(solrClient).request(any(UpdateRequest.class),
eq("test_collection"));
+ verify(solrClient, never()).add(anyString(),
any(SolrInputDocument.class));
+ verify(solrClient, never()).commit(anyString(), anyBoolean(),
anyBoolean(), anyBoolean());
}
@Test
@@ -300,21 +296,17 @@ class IndexingServiceTest {
}
@Test
- void indexDocuments_WithRuntimeException_ShouldRetryIndividually()
throws Exception {
+ void
indexDocuments_WithRuntimeException_ShouldPropagateWithoutRetrying() throws
Exception {
List<SolrInputDocument> docs = createMockDocuments(2);
- when(solrClient.add(eq("test_collection"), any(List.class)))
+ when(solrClient.request(any(UpdateRequest.class),
eq("test_collection")))
.thenThrow(new RuntimeException("Unexpected
error"));
- when(solrClient.add(eq("test_collection"),
any(SolrInputDocument.class))).thenReturn(null);
- when(solrClient.commit("test_collection", false, true,
true)).thenReturn(null);
+ assertThrows(RuntimeException.class, () ->
indexingService.indexDocuments("test_collection", docs));
- int result = indexingService.indexDocuments("test_collection",
docs);
-
- assertEquals(2, result);
- verify(solrClient).add(eq("test_collection"),
any(Collection.class));
- verify(solrClient, times(2)).add(eq("test_collection"),
any(SolrInputDocument.class));
- verify(solrClient).commit("test_collection", false, true, true);
+ verify(solrClient).request(any(UpdateRequest.class),
eq("test_collection"));
+ verify(solrClient, never()).add(anyString(),
any(SolrInputDocument.class));
+ verify(solrClient, never()).commit(anyString(), anyBoolean(),
anyBoolean(), anyBoolean());
}
private List<SolrInputDocument> createMockDocuments(int count) {