This is an automated email from the ASF dual-hosted git repository.
dsmiley pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/solr.git
The following commit(s) were added to refs/heads/main by this push:
new 428b6250e59 SOLR-7177: include the target URL when a
ConcurrentUpdateSolrClient fails to connect (#4638)
428b6250e59 is described below
commit 428b6250e5977b3643e3e2796417d17eabf9d3e4
Author: Serhiy Bzhezytskyy <[email protected]>
AuthorDate: Wed Sep 2 06:26:45 2026 +0300
SOLR-7177: include the target URL when a ConcurrentUpdateSolrClient fails
to connect (#4638)
ConcurrentUpdateSolrClient now identifies the target server when an update
fails to connect, instead of reporting a bare connection error with no URL.
---
.../SOLR-7177-cusc-connection-error-url.yml | 11 +++
.../solrj/impl/ConcurrentUpdateBaseSolrClient.java | 8 ++-
.../impl/ConcurrentUpdateSolrClientTestBase.java | 84 ++++++++++++++++++++++
3 files changed, 102 insertions(+), 1 deletion(-)
diff --git a/changelog/unreleased/SOLR-7177-cusc-connection-error-url.yml
b/changelog/unreleased/SOLR-7177-cusc-connection-error-url.yml
new file mode 100644
index 00000000000..f9743b7fcf5
--- /dev/null
+++ b/changelog/unreleased/SOLR-7177-cusc-connection-error-url.yml
@@ -0,0 +1,11 @@
+# See https://github.com/apache/solr/blob/main/dev-docs/changelog.adoc
+
+title: >
+ ConcurrentUpdateSolrClient now identifies the target server when an update
fails to connect,
+ instead of reporting a bare connection error with no URL.
+type: fixed
+authors:
+ - name: Serhiy Bzhezytskyy
+links:
+ - name: SOLR-7177
+ url: https://issues.apache.org/jira/browse/SOLR-7177
diff --git
a/solr/solrj/src/java/org/apache/solr/client/solrj/impl/ConcurrentUpdateBaseSolrClient.java
b/solr/solrj/src/java/org/apache/solr/client/solrj/impl/ConcurrentUpdateBaseSolrClient.java
index ce4c8673bb4..5baeaec60a9 100644
---
a/solr/solrj/src/java/org/apache/solr/client/solrj/impl/ConcurrentUpdateBaseSolrClient.java
+++
b/solr/solrj/src/java/org/apache/solr/client/solrj/impl/ConcurrentUpdateBaseSolrClient.java
@@ -340,8 +340,14 @@ public abstract class ConcurrentUpdateBaseSolrClient
extends SolrClient {
} catch (OutOfMemoryError | InterruptedException e) {
throw e;
- } catch (Throwable e) {
+ } catch (RemoteSolrException e) {
handleError(e, docIds, collection);
+ } catch (Throwable e) {
+ handleError(
+ new SolrServerException(
+ "Error from server at " + basePath + ": " +
e.getMessage(), e),
+ docIds,
+ collection);
} finally {
try {
consumeFully(rspBody);
diff --git
a/solr/solrj/src/test/org/apache/solr/client/solrj/impl/ConcurrentUpdateSolrClientTestBase.java
b/solr/solrj/src/test/org/apache/solr/client/solrj/impl/ConcurrentUpdateSolrClientTestBase.java
index 7a4c387e408..c3e9184cec5 100644
---
a/solr/solrj/src/test/org/apache/solr/client/solrj/impl/ConcurrentUpdateSolrClientTestBase.java
+++
b/solr/solrj/src/test/org/apache/solr/client/solrj/impl/ConcurrentUpdateSolrClientTestBase.java
@@ -399,6 +399,90 @@ public abstract class ConcurrentUpdateSolrClientTestBase
extends SolrTestCaseJ4
"the per-id callback should not fire for a non-document error", 0,
richCalls.get());
}
+ /**
+ * A connection failure surfaces the target URL so the failing server is
identifiable, rather than
+ * a bare socket error with no context.
+ */
+ @Test
+ public void testConnectionErrorIncludesUrl() throws Exception {
+ String unreachable = "http://127.0.0.1:1/solr"; // nothing listening ->
connect failure
+ List<Throwable> errors = new CopyOnWriteArrayList<>();
+ ConcurrentUpdateBaseSolrClient.UpdateErrorHandler handler =
+ new ConcurrentUpdateBaseSolrClient.UpdateErrorHandler() {
+ @Override
+ public void onError(Throwable ex, List<String> ids, String
collection) {
+ errors.add(ex);
+ }
+
+ @Override
+ public void onError(Throwable ex) {
+ errors.add(ex);
+ }
+ };
+
+ try (var httpClient = solrClient(null);
+ var concurrentClient =
+ errorHandlerConcurrentClient(unreachable, 10, 2, httpClient,
handler)) {
+ SolrInputDocument doc = new SolrInputDocument();
+ doc.addField("id", "doc-1");
+ concurrentClient.add("collection1", doc);
+ concurrentClient.blockUntilFinished();
+ }
+
+ assertFalse("expected a connection error to be reported",
errors.isEmpty());
+ boolean anyMentionsUrl =
+ errors.stream()
+ .anyMatch(
+ e -> {
+ for (Throwable t = e; t != null; t = t.getCause()) {
+ if (t.getMessage() != null &&
t.getMessage().contains("127.0.0.1:1")) {
+ return true;
+ }
+ }
+ return false;
+ });
+ assertTrue(
+ "connection error should identify the target server; got: " + errors,
anyMentionsUrl);
+ }
+
+ /**
+ * A connection error is reported as a SolrServerException that preserves
the original cause, so
+ * SolrCmdDistributor's checkRetry can unwrap it via getRootCause to decide
whether to retry.
+ */
+ @Test
+ public void testConnectionErrorIsSolrServerExceptionPreservingCause() throws
Exception {
+ String unreachable = "http://127.0.0.1:1/solr";
+ List<Throwable> errors = new CopyOnWriteArrayList<>();
+ ConcurrentUpdateBaseSolrClient.UpdateErrorHandler handler =
+ new ConcurrentUpdateBaseSolrClient.UpdateErrorHandler() {
+ @Override
+ public void onError(Throwable ex, List<String> ids, String
collection) {
+ errors.add(ex);
+ }
+
+ @Override
+ public void onError(Throwable ex) {
+ errors.add(ex);
+ }
+ };
+
+ try (var httpClient = solrClient(null);
+ var concurrentClient =
+ errorHandlerConcurrentClient(unreachable, 10, 2, httpClient,
handler)) {
+ SolrInputDocument doc = new SolrInputDocument();
+ doc.addField("id", "doc-1");
+ concurrentClient.add("collection1", doc);
+ concurrentClient.blockUntilFinished();
+ }
+
+ assertFalse("expected a connection error to be reported",
errors.isEmpty());
+ Throwable reported = errors.get(0);
+ assertTrue(
+ "connection error should be wrapped as SolrServerException; got: " +
reported,
+ reported instanceof SolrServerException);
+ assertNotNull("the original cause must be preserved", reported.getCause());
+ }
+
/**
* A naive lambda handler only registers for per-id failures; an error not
tied to identifiable
* documents is logged by the default general callback and does not stop the
client.