diff --git a/core/pom.xml b/core/pom.xml
index 2531c941..5052b74b 100644
--- a/core/pom.xml
+++ b/core/pom.xml
@@ -54,6 +54,14 @@
io.github.openfeign.form
feign-form
+
+ io.github.resilience4j
+ resilience4j-feign
+
+
+ io.github.resilience4j
+ resilience4j-retry
+
io.openapitools.jackson.dataformat
jackson-dataformat-hal
diff --git a/core/src/main/java/com/adobe/aio/util/feign/FeignUtil.java b/core/src/main/java/com/adobe/aio/util/feign/FeignUtil.java
index b3bac24c..5ad38ce4 100644
--- a/core/src/main/java/com/adobe/aio/util/feign/FeignUtil.java
+++ b/core/src/main/java/com/adobe/aio/util/feign/FeignUtil.java
@@ -15,17 +15,26 @@
import feign.Feign;
import feign.Logger.Level;
import feign.Request;
+import feign.RetryableException;
+import feign.Retryer;
import feign.form.FormEncoder;
import feign.jackson.JacksonDecoder;
import feign.jackson.JacksonEncoder;
import feign.optionals.OptionalDecoder;
import feign.slf4j.Slf4jLogger;
+import io.github.resilience4j.core.IntervalFunction;
+import io.github.resilience4j.feign.FeignDecorators;
+import io.github.resilience4j.feign.Resilience4jFeign;
+import io.github.resilience4j.retry.Retry;
+import io.github.resilience4j.retry.RetryConfig;
import java.util.concurrent.TimeUnit;
+import java.util.function.Function;
public class FeignUtil {
public static final int DEFAULT_CONNECT_TIMEOUT_IN_SECONDS = 10;
public static final int DEFAULT_READ_TIMEOUT_IN_SECONDS = 60;
+ private static final long DEFAULT_RETRY_INITIAL_INTERVAL_IN_MILLISECONDS = 2000;
private FeignUtil() {
}
@@ -35,10 +44,39 @@ private FeignUtil() {
* our global read and time out options
*/
public static Feign.Builder getBaseBuilder() {
- return Feign.builder()
+ return getBaseBuilder(DEFAULT_RETRY_INITIAL_INTERVAL_IN_MILLISECONDS);
+ }
+
+ public static Feign.Builder getBaseBuilder(long initialIntervalMillis) {
+ final IntervalFunction exponentialBackoff = IntervalFunction
+ .ofExponentialBackoff(initialIntervalMillis, 2.0);
+ FeignDecorators decorators = FeignDecorators.builder()
+ .withRetry(Retry.of("default", RetryConfig.custom()
+ .maxAttempts(3)
+ .retryOnException((t) -> t instanceof RetryableException)
+ .intervalBiFunction((attempt, result) -> result
+ .bimap(
+ e -> {
+ if (e instanceof RetryableException) {
+ RetryableException ex = (RetryableException) e;
+ if (ex.retryAfter() != null) {
+ long interval = System.currentTimeMillis() - ex.retryAfter().getTime();
+ return Math.max(exponentialBackoff.apply(attempt), interval);
+ }
+ }
+ return exponentialBackoff.apply(attempt);
+ },
+ r -> exponentialBackoff.apply(attempt)
+ )
+ .fold(Function.identity(), Function.identity())
+ )
+ .build())
+ ).build();
+ return Resilience4jFeign.builder(decorators)
.logger(new Slf4jLogger())
//.logLevel(Level.BASIC)
.logLevel(Level.NONE)
+ .retryer(Retryer.NEVER_RETRY)
//.logLevel(Level.FULL) // use this instead when debugging
.decode404()
.errorDecoder(new IOErrorDecoder())
@@ -51,7 +89,11 @@ public static Feign.Builder getBaseBuilder() {
* logger and our global read and time out options
*/
public static Feign.Builder getDefaultBuilder() {
- return getBaseBuilder()
+ return getDefaultBuilder(DEFAULT_RETRY_INITIAL_INTERVAL_IN_MILLISECONDS);
+ }
+
+ public static Feign.Builder getDefaultBuilder(long initialIntervalMillis) {
+ return getBaseBuilder(initialIntervalMillis)
.decoder(new OptionalDecoder(new JacksonDecoder(JacksonUtil.DEFAULT_OBJECT_MAPPER)))
.encoder(new JacksonEncoder(JacksonUtil.DEFAULT_OBJECT_MAPPER));
@@ -62,7 +104,11 @@ public static Feign.Builder getDefaultBuilder() {
* global read and time out options, and form encoder
*/
public static Feign.Builder getBuilderWithFormEncoder() {
- return getBaseBuilder()
+ return getBaseBuilder(DEFAULT_RETRY_INITIAL_INTERVAL_IN_MILLISECONDS);
+ }
+
+ public static Feign.Builder getBuilderWithFormEncoder(long initialIntervalMillis) {
+ return getBaseBuilder(initialIntervalMillis)
.decoder(new OptionalDecoder(new JacksonDecoder(JacksonUtil.DEFAULT_OBJECT_MAPPER)))
.encoder(new FormEncoder());
}
diff --git a/ims/src/main/java/com/adobe/aio/ims/feign/FeignImsService.java b/ims/src/main/java/com/adobe/aio/ims/feign/FeignImsService.java
index f5c0ec97..faba4fbe 100644
--- a/ims/src/main/java/com/adobe/aio/ims/feign/FeignImsService.java
+++ b/ims/src/main/java/com/adobe/aio/ims/feign/FeignImsService.java
@@ -17,6 +17,7 @@
import com.adobe.aio.ims.api.ImsApi;
import com.adobe.aio.ims.model.AccessToken;
import com.adobe.aio.util.feign.FeignUtil;
+import feign.Retryer;
public class FeignImsService implements ImsService {
diff --git a/pom.xml b/pom.xml
index 432a0a64..7e151051 100644
--- a/pom.xml
+++ b/pom.xml
@@ -113,6 +113,7 @@
11.2
3.8.0
+ 1.7.0
@@ -212,6 +213,17 @@
${feign-form.version}
+
+ io.github.resilience4j
+ resilience4j-feign
+ ${resilience4j.version}
+
+
+ io.github.resilience4j
+ resilience4j-retry
+ ${resilience4j.version}
+
+
junit
junit