Project Reactor - Using repeat and repeatWhen

This tutorial shows you how to repeat the execution of a method that returns Reactor's reactive types, either Mono or Flux.

Please note that repeat and repeatWhen only work as long as the method doesn't throw error. If you want to retry execution when error occurs, you can use retry or retryWhen.

In this tutorial, we're going to repeat the execution of this method.

  public class MyClass {
  
      private Mono myMethod() {
          System.out.println("execute myMethod");
  
          return Mono.just("Value");
      }
  }

How repeat and repeat Work

If you apply repeat or repeatWhen on a method that returns Reactor's types, the method will be re-subscribed if the repeat condition fulfilled. It only executes the method once and using repeat makes the method re-subscribed again.

The following example will not execute myMethod when repeat occurs as it's only re-subscribed.

  myClass.myMethod()
          .repeat()
          .blockLast()

To make myMethod executed at every repeat, you can wrap it inside Mono.defer.

  Mono.defer(() -> myClass.myMethod())
          .repeat()
          .blockLast()

For method that returns Flux, use Flux.defer instead.

  Flux.defer(() -> myClass.myFluxMethod())
          .repeat()
          .blockLast()

Alternatively, you can use Mono.fromSupplier and flatten the result.

  Mono.fromSupplier(myClass::myMethod).flatMap(Function.identity())
          .repeat()
          .blockLast()

Using repeat

Repeat Forever

If you want to repeat the the method without limit, just use .repeat().

  Mono.fromSupplier(myClass::myMethod).flatMap(Function.identity())
          .repeat()
          .blockLast()

Repeat N Times

If you want to repeat it for n times, you can use .repeat(long numRepeat).

  Mono.fromSupplier(myClass::myMethod).flatMap(Function.identity())
          .repeat(10)
          .blockLast()

Repeat using BooleanSupplier

If you want to use another method to determine whether it's should be repeated again or not, you can pass a BooleanSupplier - a supplier of boolean-valued result. It works by evaluating a method that returns boolean to determine whether it should re-subscribe. For example, you can create something like this:

    private boolean shouldRepeat() {
      return true;
  }

Then, use it as shown on the code below

  Mono.defer(() -> myClass.myMethod())
                  .repeat(myClass::shouldRepeat)
                  .blockLast()

It will repeat every time shouldRepeat returns true.

If you want to use BooleanSupplier as well as limiting the retry number at the same time, you can pass the limit number as first argument and the BooleanSupplier as the second argument.

  Mono.defer(() -> myClass.myMethod())
                  .repeat(5, myClass::shouldRepeat)
                  .blockLast()

In the above example, even if shouldRepeat always returns true, the repeat will be limited at 5.

Using repeatWhen

With repeatWhen, we can pass a function to control the repeat. For example, we can use zipWith to limit and keep track the number of repeats and use the repeat number to create an exponential delay.

  Mono.defer(() -> myClass.myMethod())
                  .repeatWhen(repeat -> repeat.zipWith(Flux.range(1, 5), (e, idx) -> idx)
                          .flatMap(time -> Mono.delay(Duration.ofSeconds(time)))
                  )
                  .blockLast()