0

The retry-logic is implemented in WebClientConfig.ExchangeFilterFunction. I would like to implement similar with repeatWhenEmpty operator.

Uses:

  • Java 1.8
  • Spring Boot Version 2.1X
  • Project Reactor Addons 3.1.6

Configuration:

@Slf4j
@Configuration
public class WebClientConfig {

     private static final String host = "https://google.com";  //test host

     @Bean
     public WebClient retryingClient(WebClient.Builder builder) {
        return builder
              .baseUrl(host)
              .filter(retryFilter())
              .build();
     }

     private ExchangeFilterFunction retryFilter() {
          AtomicInteger counter = new AtomicCounter();

          return ((request, next) ->
              next.exchange(request)
                  .log()
                  .doOnNext(clientResponse -> {
                       log.info(Request: {} {}", request.method(), request.url());

                       HttpStatus status = clientResponse.statusCode();

                       if (status == HttpStatus.ACCEPTED) { //retry if the client returns 202
                            counter.incrementAndGet();
                            log.info("Retrying : {}", counter.get());
                            throw new RetryException("Retrying - " + counter.get());
                       } else if (status.isError()) {
                            log.info("Error, status code : {}", clientResponse.statusCode);
                            throw new RuntimeException("Status code : " + clientResponse.statusCode);
                       }
                  }).retryWhen(Retry.anyOf(RetryException.class)
                    .exponentialBackoff(Duration.ofMillis(100), Duration.ofMillis(500))
                    .retryMax(4));
      }
}

This is the service that uses the webClient configured above.

@Service
@Slf4j
public class ExternalCallService {
     private final WebClient webClient;
     private static final String path = "/flights";  //test url

     public ExternalCallService(@Qualifier("retryingClient") WebClient webClient) {
          this.webClient = webClient;
     }

     public Flux<String> fetchFlights(String query) {
          return webClient
                .get()
                .uri(uri -> uri.path(path).queryParam("filter", query).build())
                .exchange()
                .flatMap(response -> response.bodyToFlux(String.class));

    }

}

Runtime exception to help trigger retry

public class RetryException extends RuntimeException {
     public RetryException(String msg) {
          super(msg);
     }
}

Note: I am mostly typing this code in here, please excuse my typo or missing semicolon (if any). I will try to add more details if needed.

gkc123
  • 512
  • 1
  • 7
  • 24
  • you are saying you are "unable to implement the same functionality" but you have not posted any of the code you have tried or any of the specifics as to WHAT is not working. – Toerktumlare Mar 08 '20 at 22:15
  • `repeatWhenEmpty` is for mono. You might want to switch to Mono – vins Mar 08 '20 at 22:59
  • I do not, you could try replacing retryWhen with repeatWhen plus simple delay functionality. I also modified the title of the post to `How to...?` – gkc123 Mar 08 '20 at 23:27

1 Answers1

0

Is this what you're looking for?

.repeatWhen(emitted -> emitted
        .zipWith(Flux.range(1, 4)) // do repeat 4 times
        .flatMap(t -> Mono
                // exponential backoff, you can play around this
                // to get a desired backoff value
                .delay(Duration.ofMillis(100 * t.getT2()))
        )
)
Stepan Tsybulski
  • 1,121
  • 8
  • 18
  • 1
    this is very similar to `repeatWhen(Repeat.times(4).fixedBackoff(Duration.ofMillis(100)));`. I am looking for the condition `Repeat.onlyIf(repeatContext -> ...`. The logic is to repeat the same call when the status code from the webClient returns the value of 202. – gkc123 Mar 10 '20 at 03:40