You can add a Retryer in the FeignClientConfig
@Configuration
public class FeignClientConfig {
@Bean
public Retryer retryer() {
return new Custom();
}
}
class Custom implements Retryer {
private final int maxAttempts;
private final long backoff;
int attempt;
public Custom() {
this(2000, 3);
}
public Custom(long backoff, int maxAttempts) {
this.backoff = backoff;
this.maxAttempts = maxAttempts;
this.attempt = 1;
}
public void continueOrPropagate(RetryableException e) {
if (attempt++ >= maxAttempts) {
throw e;
}
try {
Thread.sleep(backoff);
} catch (InterruptedException ignored) {
Thread.currentThread().interrupt();
}
}
@Override
public Retryer clone() {
return new Custom(backoff, maxAttempts);
}
}
Updated with sample Retryer example config based on the Retryer.Default.
You can add a Retryer in the FeignClientConfig
@Configuration
public class FeignClientConfig {
@Bean
public Retryer retryer() {
return new Custom();
}
}
class Custom implements Retryer {
private final int maxAttempts;
private final long backoff;
int attempt;
public Custom() {
this(2000, 3);
}
public Custom(long backoff, int maxAttempts) {
this.backoff = backoff;
this.maxAttempts = maxAttempts;
this.attempt = 1;
}
public void continueOrPropagate(RetryableException e) {
if (attempt++ >= maxAttempts) {
throw e;
}
try {
Thread.sleep(backoff);
} catch (InterruptedException ignored) {
Thread.currentThread().interrupt();
}
}
@Override
public Retryer clone() {
return new Custom(backoff, maxAttempts);
}
}
Updated with sample Retryer example config based on the Retryer.Default.
Just new a contructor Default
@Configuration
public class FeignClientConfig {
@Bean
public Retryer retryer() {
return new Retryer.Default(100, 2000, 3);
}
}
Feign has a build in Retryer however you can not configure the Retryer via application.yml. I guess the Spring Boot Team assumed that people would use the deprecated Hystrix project for this matter.
Instead of configuring Feign by config you could write a bit of code: https://cloud.spring.io/spring-cloud-openfeign/reference/html/index.html#creating-feign-clients-manually
In addition you have to map the corresponding status code to RetryableException using a custom ErrorDecoder.
public class CustomErrorDecoder implements ErrorDecoder {
private final ErrorDecoder errorDecoder = new Default();
@Override
public Exception decode(String methodKey, Response response) {
Exception exception = defaultErrorDecoder.decode(s, response);
if(exception instanceof RetryableException){
return exception;
}
if(response.status() == 499){
return new RetryableException("499 blub", response.request().httpMethod(), null );
}
return exception;
}
}
public class Example {
public static void main(String[] args) {
MyApi myApi = Feign.builder()
.errorDecoder(new CustomErrorDecoder())
.target(MyApi.class, "https://api.hostname.com");
}
}
You can use retryable annotation.
Ex: You can throw custom exception when http status code is equal to 404
@Service
public interface MyService {
@Retryable(value = CustomException.class, maxAttempts = 2, backoff = @Backoff(delay = 100))
void retry(String str) throws CustomException;
}