http-client-branch: improve test stability by allowing retry on java.net.ConnectException
--- a/src/java.net.http/share/classes/jdk/internal/net/http/MultiExchange.java Tue May 15 16:10:17 2018 +0100
+++ b/src/java.net.http/share/classes/jdk/internal/net/http/MultiExchange.java Fri May 18 15:23:56 2018 +0100
@@ -27,6 +27,7 @@
import java.io.IOException;
import java.lang.System.Logger.Level;
+import java.net.ConnectException;
import java.time.Duration;
import java.util.Iterator;
import java.util.LinkedList;
@@ -290,8 +291,17 @@
return false;
}
+ private static boolean retryConnect() {
+ String s = Utils.getNetProperty("jdk.httpclient.disableRetryConnect");
+ if (s == "" || "true".equals(s))
+ return false;
+ return true;
+ }
+
/** True if ALL ( even non-idempotent ) requests can be automatic retried. */
private static final boolean RETRY_ALWAYS = retryPostValue();
+ /** True if ConnectException should cause a retry. Enabled by default */
+ private static final boolean RETRY_CONNECT = retryConnect();
/** Returns true is given request has an idempotent method. */
private static boolean isIdempotentRequest(HttpRequest request) {
@@ -307,13 +317,23 @@
/** Returns true if the given request can be automatically retried. */
private static boolean canRetryRequest(HttpRequest request) {
+ if (RETRY_ALWAYS)
+ return true;
if (isIdempotentRequest(request))
return true;
- if (RETRY_ALWAYS)
- return true;
return false;
}
+ private boolean retryOnFailure(Throwable t) {
+ return t instanceof ConnectionExpiredException
+ || (RETRY_CONNECT && (t instanceof ConnectException));
+ }
+
+ private Throwable retryCause(Throwable t) {
+ Throwable cause = t instanceof ConnectionExpiredException ? t.getCause() : t;
+ return cause == null ? t : cause;
+ }
+
/**
* Takes a Throwable and returns a suitable CompletableFuture that is
* completed exceptionally, or null.
@@ -326,21 +346,20 @@
}
if (cancelled && t instanceof IOException) {
t = new HttpTimeoutException("request timed out");
- } else if (t instanceof ConnectionExpiredException) {
- Throwable cause = t;
- if (t.getCause() != null) {
- cause = t.getCause(); // unwrap the ConnectionExpiredException
- }
+ } else if (retryOnFailure(t)) {
+ Throwable cause = retryCause(t);
- if (!canRetryRequest(currentreq)) {
- return failedFuture(cause); // fails with original cause
+ if (!(t instanceof ConnectException)) {
+ if (!canRetryRequest(currentreq)) {
+ return failedFuture(cause); // fails with original cause
+ }
}
// allow the retry mechanism to do its work
retryCause = cause;
if (!expiredOnce) {
if (debug.on())
- debug.log("ConnectionExpiredException (async): retrying...", t);
+ debug.log(t.getClass().getSimpleName() + " (async): retrying...", t);
expiredOnce = true;
// The connection was abruptly closed.
// We return null to retry the same request a second time.
@@ -350,9 +369,11 @@
previousreq = currentreq;
return null;
} else {
- if (debug.on())
- debug.log("ConnectionExpiredException (async): already retried once.", t);
- if (t.getCause() != null) t = t.getCause();
+ if (debug.on()) {
+ debug.log(t.getClass().getSimpleName()
+ + " (async): already retried once.", t);
+ }
+ t = cause;
}
}
return failedFuture(t);
@@ -364,9 +385,10 @@
}
@Override
public void handle() {
- if (debug.on())
+ if (debug.on()) {
debug.log("Cancelling MultiExchange due to timeout for request %s",
- request);
+ request);
+ }
cancel(new HttpTimeoutException("request timed out"));
}
}