Home > Spring > Spring WebFlux > Spring WebFlux: WebClient Retry Strategies

Spring WebFlux: WebClient Retry Strategies

In my last Spring WebFlux project, during the HTTP calls through WebClient, often I was not getting responses from the client. But when I tried by refreshing the page, the response was coming. There could be multiple reasons for not getting the proper response from the client, but I thought to implement retry options with WebClient. In the below, we will learn how to implement Retry in WebClient, with different strategies.

WebClient with NO Retry

Mono<String> httpMono = this.webClient
                .get()
                .uri("CLIENT_URI")
                .contentType(MediaType.APPLICATION_JSON)
                .accept(MediaType.APPLICATION_JSON)
                .acceptCharset(Charset.forName("UTF-8"))
                .retrieve()
                .bodyToMono(String.class);

WebClient with default Retry

Below way of handling retry has a major disadvantage, the retry will be forever until the response is not read.

Mono<String> httpMono = this.webClient
                .get()
                .uri("CLIENT_URI")
                .contentType(MediaType.APPLICATION_JSON)
                .accept(MediaType.APPLICATION_JSON)
                .acceptCharset(Charset.forName("UTF-8"))
                .retrieve()
                .bodyToMono(String.class)
                .retry();

WebClient with Retry Limit

In the below code, instead of retrying forever, it will retry 3 times. If in these retries the response is read it will stop and give the response else the error which is coming from the client.

Mono<String> httpMono = this.webClient
                .get()
                .uri("CLIENT_URI")
                .contentType(MediaType.APPLICATION_JSON)
                .accept(MediaType.APPLICATION_JSON)
                .acceptCharset(Charset.forName("UTF-8"))
                .retrieve()
                .bodyToMono(String.class)
                .retry(3);

The above option will not make any delay in the subsequent call, else it will fire one after the another, so this is not a proper way of calling the client.

WebClient with Retry Limit using retryWhen

Mono<String> httpMono = this.webClient
                .get()
                .uri("CLIENT_URI")
                .contentType(MediaType.APPLICATION_JSON)
                .accept(MediaType.APPLICATION_JSON)
                .acceptCharset(Charset.forName("UTF-8"))
                .retrieve()
                .bodyToMono(String.class)
                .retryWhen(Retry.max(3));

The code above is the same as the previous example, but from here we will be introducing the functionality of webclient retry using retryWhen strategies.

WebClient with Retry Limit and Delay Using retryWhen

Mono<String> httpMono = this.webClient
                .get()
                .uri("CLIENT_URI")
                .contentType(MediaType.APPLICATION_JSON)
                .accept(MediaType.APPLICATION_JSON)
                .acceptCharset(Charset.forName("UTF-8"))
                .retrieve()
                .bodyToMono(String.class)
                .retryWhen(Retry.fixedDelay(3, Duration.ofSeconds(2)));

The above code will retry 3 times and every retry call would be in a delay of 2 seconds from the previous one. This strategy will pause for 3 seconds before making the next retry to the client.

Retry backOff

Mono<String> httpMono = this.webClient
                .get()
                .uri("CLIENT_URI")
                .contentType(MediaType.APPLICATION_JSON)
                .accept(MediaType.APPLICATION_JSON)
                .acceptCharset(Charset.forName("UTF-8"))
                .retrieve()
                .bodyToMono(String.class)
                .retryWhen(Retry.backoff(3, Duration.ofSeconds(2)));

The code is the same as that of the last example the only difference is that using the backOff we are using the strategy not to call the client in a fixed delay of time but to call after waiting a much longer time to the one provided. So, in the above code, we are telling to retry 3 times using a minimum delay of 2 seconds between every retry call.

Conditional Retry – Retry if Error is not 5xx

Here we will configure the webclient not to retry if the exception we are getting is 5xx. For that, we will create a filter and that filter will let us know when to retry and when not.

   Mono<String> httpMono = this.webClient
                .get()
                .uri("CLIENT_URI")
                .contentType(MediaType.APPLICATION_JSON)
                .accept(MediaType.APPLICATION_JSON)
                .acceptCharset(Charset.forName("UTF-8"))
                .retrieve()
                .bodyToMono(String.class)
                .retryWhen(Retry.backoff(3, Duration.ofSeconds(2))
                                .filter(ex -> is5xxException(ex)));

   public boolean is5xxException(Throwable ex) {
		boolean retryFlag = false;
		
		if (ex instanceof MyCustomException) {
			MyCustomException mce = (MyCustomException)ex;
			retryFlag = (mce.getStatusCode() > 499 && mce.getStatusCode() < 600);
		}
		
		return retryFlag;
	};