-
Notifications
You must be signed in to change notification settings - Fork 861
SOLR-18402: Consolidate wasRequestUnsent / wasCommError (retry) logic #4829
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
eba410e
b55044b
18fcce9
1100f03
ae65389
9a90853
29c17d0
5d646f6
7ad47d9
4a09575
57cc8e6
f7b3a9b
308961d
2b88ce8
82aabf7
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,9 @@ | ||
| title: > | ||
| SolrJ transports now classify their own failures via SolrClient.wasRequestUnsent / | ||
| wasCommError, and CloudSolrClient replays an update only when the transport proves it unsent | ||
| type: changed | ||
| authors: | ||
| - name: Han Chan | ||
| links: | ||
| - name: SOLR-18402 | ||
| url: https://issues.apache.org/jira/browse/SOLR-18402 |
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. These seem HttpSolrClient worthy and not generalized to any SolrClient (e.g. not EmbeddedSolrServer). Even not worthy of CloudSolrClient since it's really the backing HttpSolrClient, which CSC exposes. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -1194,6 +1194,23 @@ public final NamedList<Object> request(final SolrRequest<?> request) | |
| return request(request, null); | ||
| } | ||
|
|
||
| /** | ||
| * Whether the failure proves the request never reached the server, making a replay safe even when | ||
| * the request isn't idempotent. Only the transport can answer this; the default is {@code false}, | ||
| * meaning "cannot tell" rather than "the request was sent". | ||
| */ | ||
| public boolean wasRequestUnsent(Throwable t) { | ||
| return false; | ||
| } | ||
|
|
||
| /** | ||
| * Whether this is a transport-level communication failure rather than a response from the server. | ||
| * Implementations must keep {@link #wasRequestUnsent} a subset of this. | ||
| */ | ||
| public boolean wasCommError(Throwable t) { | ||
| return false; | ||
| } | ||
|
|
||
|
Comment on lines
+1197
to
+1213
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I generated this JIRA description with AI, and I did read it. But I confess now (and I recall then as well), I'm confused on the distinction between these 2 methods. It's not clear to me why we need a distinction between these two. Feel free to help me figure this out ;-) |
||
| /** | ||
| * This method defines the context in which this Solr client is being used (e.g. for internal | ||
| * communication between Solr nodes or as an external client). The default value is {@code | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -20,10 +20,8 @@ | |
| import java.io.IOException; | ||
| import java.lang.invoke.MethodHandles; | ||
| import java.lang.ref.WeakReference; | ||
| import java.net.ConnectException; | ||
| import java.net.SocketException; | ||
| import java.net.SocketTimeoutException; | ||
| import java.net.http.HttpConnectTimeoutException; | ||
| import java.util.ArrayList; | ||
| import java.util.Arrays; | ||
| import java.util.Collection; | ||
|
|
@@ -43,7 +41,6 @@ | |
| import java.util.concurrent.atomic.AtomicInteger; | ||
| import java.util.stream.Collectors; | ||
| import org.apache.solr.client.solrj.RemoteSolrException; | ||
| import org.apache.solr.client.solrj.RequestNotSentException; | ||
| import org.apache.solr.client.solrj.SolrClient; | ||
| import org.apache.solr.client.solrj.SolrRequest; | ||
| import org.apache.solr.client.solrj.SolrRequest.SolrRequestType; | ||
|
|
@@ -656,7 +653,7 @@ protected Exception doRequest( | |
| throw e; | ||
| } | ||
| } catch (SocketException e) { | ||
| if (!isNonRetryable || e instanceof ConnectException) { | ||
| if (!isNonRetryable || getClient(baseUrl).wasRequestUnsent(e)) { | ||
| ex = (!isZombie) ? makeServerAZombie(baseUrl, e) : e; | ||
| } else { | ||
| throw e; | ||
|
|
@@ -672,31 +669,27 @@ protected Exception doRequest( | |
| if (!isNonRetryable | ||
| && (rootCause instanceof IOException || rootCause instanceof TimeoutException)) { | ||
| ex = (!isZombie) ? makeServerAZombie(baseUrl, e) : e; | ||
| } else if (isNonRetryable | ||
| && (isConnectException(rootCause) | ||
| || SolrException.hasCause(e, RequestNotSentException.class))) { | ||
| } else if (isNonRetryable && getClient(baseUrl).wasRequestUnsent(e)) { | ||
| // Nothing of the request reached the server, so replaying it elsewhere is safe even though | ||
| // it isn't idempotent. | ||
| ex = (!isZombie) ? makeServerAZombie(baseUrl, e) : e; | ||
| } else { | ||
| throw e; | ||
| } | ||
| } catch (IOException e) { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. An implicit outcome of SOLR-18402, I think, is to massively simplify catch blocks that currently are overly complex. Adding an IOException here and not simplifying or generalizing the previous ones is counter to this direction. |
||
| // A transport may throw one directly rather than wrapping it in a SolrServerException. | ||
| if (!isNonRetryable || getClient(baseUrl).wasRequestUnsent(e)) { | ||
| ex = (!isZombie) ? makeServerAZombie(baseUrl, e) : e; | ||
| } else { | ||
| throw e; | ||
| } | ||
| } catch (Exception e) { | ||
| throw new SolrServerException(e); | ||
| } | ||
|
|
||
| return ex; | ||
| } | ||
|
|
||
| protected boolean isConnectException(Throwable t) { | ||
| if (t instanceof ConnectException || t instanceof HttpConnectTimeoutException) { | ||
| return true; | ||
| } | ||
| // Check for common connection timeout exceptions by name to avoid hard dependencies on | ||
| // specific HTTP client libraries (e.g., Jetty or Apache HttpClient). | ||
| return t != null && t.getClass().getName().endsWith("ConnectTimeoutException"); | ||
| } | ||
|
|
||
| protected abstract SolrClient getClient(Endpoint endpoint); | ||
|
|
||
| private void startAliveCheckExecutor() { | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think this is worth putting in the ref guide. It's a detail and doesn't change how people use SolrJ.