tangyaya
tangyaya

Reputation: 49

Spring Reactor Retry.retryWhen() did not work

how to use retry? i want to retry to call method when error until it`s successed. my test code


@Test
    public void fun1() throws InterruptedException {
        this.generate()
                .retryWhen(Retry.fixedDelay(5, Duration.ofMillis(1))
                        .filter(e -> e instanceof Exception)
                        .doBeforeRetry(res -> System.out.println("retry begin"))
                        .doAfterRetry(res -> System.out.println("try finished")))
                .onErrorContinue((throwable, o) -> System.out.println(throwable))
                .subscribe(System.out::println);
    }

    private Mono<String> generate() throws InterruptedException {
        if (retryTime.get() == 3) {
            return Mono.just("Hello");
        }
        System.out.println("i am called" + retryTime.getAndAdd(1));
        return Mono.error(new IllegalArgumentException("exception test"));
    }

** but get this result**

i am called1
10:02:12.104 [main] DEBUG reactor.util.Loggers - Using Slf4j logging framework
retry begin
try finished
retry begin
try finished
retry begin
try finished
retry begin
try finished
retry begin
try finished
reactor.core.Exceptions$RetryExhaustedException: Retries exhausted: 5/5

Process finished with exit code 0

why not retry three times until success???

Upvotes: 3

Views: 6774

Answers (1)

Phil Clay
Phil Clay

Reputation: 4536

Retry works by re-subscribing to the result of the upstream methods. It does not re-invoke the upstream methods.

In your case specifically, each subscription from .retryWhen is subscribing to the Mono.error returned from the single call to generate(). Therefore, each subscription sees the same exception result.

To fix this, you need to defer the logic inside the generate() method to occur at subscription time, rather than assembly time.

For example, use Mono.fromCallable, like this:

    private Mono<String> generate() {
        return Mono.fromCallable(() -> {
            if (retryTime.get() == 3) {
                return "Hello";
            }
            System.out.println("i am called" + retryTime.getAndAdd(1));
            throw new new IllegalArgumentException("exception test");
        });
    }

The Callable will be called for each subscriber. Specifically, it will be called each time the retryWhen operator re-subscribes.

Upvotes: 10

Related Questions