Logo

dev-resources.site

for different kinds of informations.

Spring WebFlux Retry Mechanism

Published at
4/14/2024
Categories
retry
spring
webflux
java
Author
tharindufdo
Categories
4 categories in total
retry
open
spring
open
webflux
open
java
open
Author
11 person written this
tharindufdo
open
Spring WebFlux Retry Mechanism

Microservices and other external dependencies are vulnerable to occasional failures brought on by temporary service outages, network problems, or temporary faults. These errors may only occur temporarily, and repeating the procedure again after a little break frequently results in a successful outcome. Retry mechanisms are designed to deal with these brief interruptions by repeatedly attempting to carry out a particular task until it completes or a predetermined number of retries are used up.

Maven Dependencies

Import the most recent version of the maven repository’s spring-retry dependency. Since spring retry is AOP-based, you should also use the most recent version of spring-aspects.

<dependency>
    <groupId>org.springframework.retry</groupId>
    <artifactId>spring-retry</artifactId>
    <version>2.0.3</version>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-aspects</artifactId>
    <version>6.0.11</version>
</dependency>
Enter fullscreen mode Exit fullscreen mode

1. The Basics of Retry in Spring WebFlux

Retry and retryWhen are Spring WebFlux’s two main ways for building retry mechanisms, which help handle certain scenarios gracefully.

1.1 Using retry Method:

The retry method is a simple technique in which, in the event that the web client returns an error, the application retries the request a predetermined number of times. Let’s examine a straightforward illustration:

public Mono<Item> getItemData(String itemId) {
    return webClient.get()
        .uri("/getItemData", itemId)
        .header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
        .bodyToMono(Item.class)
        .retrieve()
        .retry(3); // Here we retry for 3 Attempts
}
Enter fullscreen mode Exit fullscreen mode

1.2 Using retryWhenMethod:

We can make use of the retryWhen method for a more dynamic and flexible retry strategy. We are able to construct a more complex retry logic with this way. As an illustration, consider this:

public Mono<Item> getItemData(String itemId) {
    return webClient.get()
        .uri("/getItemData", itemId)
        .header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
        .bodyToMono(Item.class)
        .retrieve()
        .retryWhen(Retry.max(3)); // Retry up to 3 attempts
}
Enter fullscreen mode Exit fullscreen mode

Tailoring Retry Options

Let’s now customize retry techniques to better fit the unique requirements of the application on your blog. To build a more adaptable and responsive retry mechanism, we’ll utilize the backoff function inside retryWhen.

public Mono<Item> getData(String itemId) {
    return webClient.get()
        .uri("/getItemData", itemId)
        .header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
        .retrieve()
        .bodyToMono(Item.class)
        .retryWhen(Retry
            .backoff(3, Duration.ofSeconds(1)) // Retry up to 3 times with a backoff of 1 second
            .maxBackoff(Duration.ofSeconds(5)) // Maximum backoff of 5 seconds
            .doBeforeRetry(retrySignal -> {
                // You can add a custom logic here before each retry if you prefer
            })
        );
}
Enter fullscreen mode Exit fullscreen mode

Filtering Errors and Handling Exhausted Retries

A retry attempt will now be made in the event of any service problems, including 4xx errors like 400:Bad Request or 401:Unauthorized.

Since the server response won’t change, it is obvious that we shouldn’t try again with such client problems. Let’s see how we may limit the use of the retry technique to certain types of faults.

public Mono<Item> getData(String itemId) {
    return webClient.get()
        .uri("/getItemData", itemId)
        .header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
        .retrieve()
        .bodyToMono(Item.class)
        .retryWhen(Retry
            .backoff(3, Duration.ofSeconds(1)) // Retry up to 3 times with a backoff of 1 second
            .maxBackoff(Duration.ofSeconds(5)) // Maximum backoff of 5 seconds
            .doAfterRetry(retrySignal -> log.info("RETRY_ATTEMPTED | {} | Get Item Data Retry Attempted")) /
            .filter(throwable -> throwable instanceof WebClientResponseException
                && ((WebClientResponseException) throwable).getStatusCode().is5xxServerError()
                || throwable.getCause() instanceof TimeoutException)
            .onRetryExhaustedThrow((retryBackoffSpec, retrySignal) -> {
                log.info("SERVICE_UNAVAILABLE | External Service failed to process after max retries");
                throw new GeneralStatusCodeException(ApiError.SERVICE_UNAVAILABLE);
            })
        );
}
Enter fullscreen mode Exit fullscreen mode

You can customize the exception handling according to your requirements.

Conclusion

This blog covered the use of the retry and retryWhen methods to add retries to a Spring WebFlux application. We first introduced a limit on the amount of times an operation might be attempted again. Next, we used and configured a variety of ways to add a delay between tries. Finally, we implemented retrying for specific errors and customizing the behaviour when all attempts have been exhausted.

Additionally, To enable Spring Retry in an application, we need to add the @EnableRetry annotation to the configuration class. (https://www.baeldung.com/spring-retry)

References

https://www.baeldung.com/spring-webflux-retry

https://www.baeldung.com/spring-retry

Github

https://github.com/tharindu1998/retry-mechanism-springwebflux

webflux Article's
24 articles in total
Favicon
Introducing Java Library for Backend Microservice Webflux (Reactor-core)
Favicon
Making reactive applications with a Kitten Care Example
Favicon
Reactive Programming applied to Legacy Services — A WebFlux example
Favicon
Getting Started with Spring WebFlux
Favicon
Implementing Soft Delete in Spring WebFlux with R2DBC
Favicon
Java library for developing backend with reactive programming
Favicon
How to Run an Asynchronous Task in Spring WebFlux Without Blocking the Main Response?
Favicon
How to Run a Method Asynchronously in a Reactive Chain in Spring WebFlux?
Favicon
Spring WebFlux Retry Mechanism
Favicon
Implementing Context Propagation in Reactive Programming Projects 🔄
Favicon
Ability to unlearn in Software: Reactive Programming
Favicon
Create DTO using get results from repository returns duplicate values in Spring Boot Reactive WebFlux
Favicon
Spring R2DBC, MariaDB, and JSON columns
Favicon
SpringBoot WebFlux Annotation-based RestAPIs
Favicon
SpringBoot WebFlux Functional RestAPIs
Favicon
Spring Webflux testing with Mockito
Favicon
A Short Example of Real-Time Event Streaming Using Spring WebFlux
Favicon
Global Error Handling In Webflux (Reactive World)
Favicon
Spring Webflux - Reactive Java Applications - Part 2
Favicon
Building an URL Shortening API with Spring WebFlux (and a lot of supporting cast)
Favicon
Spring Webflux - Reactive Java Applications - Part 1
Favicon
Spring Webflux - Aplicações reativas em Java - Parte 1
Favicon
KVision v2.0.0 - with Bootstrap 4, Spring Webflux and lots of other improvements
Favicon
Sending Multipart Form Data Using Spring WebTestClient

Featured ones: