diff --git a/drift-client/src/main/java/io/airlift/drift/client/DriftMethodInvocation.java b/drift-client/src/main/java/io/airlift/drift/client/DriftMethodInvocation.java
index eb6d80e60..d7c264ce8 100644
--- a/drift-client/src/main/java/io/airlift/drift/client/DriftMethodInvocation.java
+++ b/drift-client/src/main/java/io/airlift/drift/client/DriftMethodInvocation.java
@@ -16,6 +16,8 @@
package io.airlift.drift.client;
import com.google.common.base.Ticker;
+import com.google.common.collect.HashMultiset;
+import com.google.common.collect.Multiset;
import com.google.common.util.concurrent.AbstractFuture;
import com.google.common.util.concurrent.FutureCallback;
import com.google.common.util.concurrent.Futures;
@@ -71,6 +73,8 @@ class DriftMethodInvocation
@GuardedBy("this")
private final Set attemptedAddresses = new LinkedHashSet<>();
@GuardedBy("this")
+ private final Multiset failedConnectionAttempts = HashMultiset.create();
+ @GuardedBy("this")
private int failedConnections;
@GuardedBy("this")
private int overloadedRejects;
@@ -104,7 +108,7 @@ static DriftMethodInvocation createDriftMethodInvocation(
stat,
ticker);
// invocation can not be started from constructor, because it may start threads that can call back into the unpublished object
- invocation.nextAttempt();
+ invocation.nextAttempt(true);
return invocation;
}
@@ -138,7 +142,7 @@ private DriftMethodInvocation(
}, directExecutor());
}
- private synchronized void nextAttempt()
+ private synchronized void nextAttempt(boolean noConnectDelay)
{
try {
// request was already canceled
@@ -156,8 +160,32 @@ private synchronized void nextAttempt()
stat.recordRetry();
}
+ if (noConnectDelay) {
+ invoke(address.get());
+ return;
+ }
+
+ int connectionFailuresCount = failedConnectionAttempts.count(address.get());
+ if (connectionFailuresCount == 0) {
+ invoke(address.get());
+ return;
+ }
+
+ Duration connectDelay = retryPolicy.getBackoffDelay(connectionFailuresCount);
+ log.debug("Failed connection to %s with attempt %s, will retry in %s", address.get(), connectionFailuresCount, connectDelay);
+ schedule(connectDelay, () -> invoke(address.get()));
+ }
+ catch (Throwable t) {
+ // this should never happen, but ensure that invocation always finishes
+ unexpectedError(t);
+ }
+ }
+
+ private synchronized void invoke(A address)
+ {
+ try {
long invocationStartTime = ticker.read();
- ListenableFuture