Feign Retry Logic Implementation in Spring Boot

feign

Introduction

In modern microservice architectures, communication between services is critical, but often these communications can fail due to network issues, service downtime, or other transient faults. To ensure resilience and avoid complete failures, it’s essential to implement retry logic for these inter-service calls. In Spring Boot, if you’re using Feign for client-side load balancing and API calls, implementing retry logic is straightforward and can greatly enhance the robustness of your system.

In this post, we’ll walk through how to implement retry logic in Feign with Spring Boot.

Setting Up Feign Client in Spring Boot

Feign is a declarative web service client that makes writing web service clients easy. You only need to declare the interfaces, and Feign handles the rest. Here’s how you can start with a basic Feign client.

First, add the necessary dependencies for Feign in your pom.xml:

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>

Enable Feign clients in your Spring Boot application by adding the annotation @EnableFeignClients to your main class:

@SpringBootApplication
@EnableFeignClients
public class LearnSpringBootOnlineApplication {
    public static void main(String[] args) {
        SpringApplication.run(LearnSpringBootOnlineApplication.class, args);
    }
}

Next, define your Feign client interface. For example, to communicate with an external service:

@FeignClient(name = "externalService", url = "https://api.external.com")
public interface ExternalServiceClient {
    
    @GetMapping("/data")
    ResponseEntity<Data> getData();
}

Implementing Retry Logic in Feign

Spring Boot’s Feign client doesn’t natively support retries out of the box, but you can implement retries by integrating Spring Retry or configuring Resilience4j for Feign. Both approaches are widely used and effective.

Using Spring Retry

To implement retry logic using Spring Retry, you first need to add the Spring Retry dependency:

<dependency>
    <groupId>org.springframework.retry</groupId>
    <artifactId>spring-retry</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>

Next, enable retry in Feign by adding the spring-retry configuration to your application.yml or application.properties:

feign:
  client:
    config:
      default:
        retryer: true

This configuration enables retry functionality in Feign. However, you’ll need to customize the retry behavior by defining a Retryer bean:

import feign.Retryer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import static java.util.concurrent.TimeUnit.SECONDS;

@Configuration
public class FeignRetryConfig {
    
    @Bean
    public Retryer retryer() {
        // Retryer(Default period, max period, max attempts)
        return new Retryer.Default(100, SECONDS.toMillis(1), 5);
    }
}

Here, we’ve configured Feign to retry up to 5 times, with a 100ms initial interval, which grows exponentially up to 1 second between retries.

Using Resilience4j

Another approach is to use Resilience4j, a lightweight fault tolerance library designed for Java. Resilience4j allows for retries, circuit breakers, rate limiters, and more. To add retry functionality using Resilience4j, you’ll need to include the following dependencies:

<dependency>
    <groupId>io.github.resilience4j</groupId>
    <artifactId>resilience4j-spring-boot2</artifactId>
</dependency>
<dependency>
    <groupId>io.github.resilience4j</groupId>
    <artifactId>resilience4j-feign</artifactId>
</dependency>

Then, configure Resilience4j retry in your application.yml:

resilience4j:
  retry:
    instances:
      externalService:
        max-attempts: 5
        wait-duration: 1000ms

Finally, annotate your Feign client with the @Retry annotation:

@FeignClient(name = "externalService", url = "https://api.external.com")
public interface ExternalServiceClient {

    @Retry(name = "externalService")
    @GetMapping("/data")
    ResponseEntity<Data> getData();
}

This will ensure that the Feign client retries the call up to 5 times with a 1-second delay between attempts.

Handling Specific Exceptions

Sometimes you may want to retry only on certain types of exceptions. For example, you might want to retry on network errors but not on 4xx HTTP errors. You can specify which exceptions should trigger a retry.

For Spring Retry:

@Bean
public Retryer retryer() {
    return new Retryer.Default(100, SECONDS.toMillis(1), 5) {
        @Override
        public boolean continueOrPropagate(RetryableException e) {
            if (e.status() >= 400 && e.status() < 500) {
                // Don't retry on 4xx errors
                return false;
            }
            return super.continueOrPropagate(e);
        }
    };
}

For Resilience4j:

resilience4j:
  retry:
    instances:
      externalService:
        max-attempts: 5
        wait-duration: 1000ms
        retry-exceptions:
          - java.io.IOException
        ignore-exceptions:
          - feign.FeignException

This configuration ensures that the retry logic is applied only to exceptions like IOException and ignores FeignException, which represents Feign-specific errors like 4xx or 5xx.

Conclusion

Retry logic is an essential mechanism to improve the resilience of your service communication. Feign, combined with Spring Retry or Resilience4j, offers a powerful way to implement retries for transient failures.

Using Spring Retry gives you a simple, declarative way to manage retries, while Resilience4j offers more advanced features, such as circuit breakers and rate limiting, alongside retry logic.

By implementing retry strategies effectively, your Spring Boot application can recover gracefully from transient errors, ensuring smoother and more reliable inter-service communication.

Explore our diverse collection of blogs covering a wide range of topics here.

Address

4232 Farnum Road, New York, New York(NY), 10029

Telephone: 212-289-5109

Mobile: 917-216-4839

Copyright © 2024 Learn Spring Boot Online