1

I cannot understand how Flux.onErrorContinue() works. Based on Does Reactor onErrorContinue operator let the original sequence continue? I created a similar example to understand it better, but I am lost.

Especially weird is the interference between onErrorContinue() and thenReturn().

I have the following code:

import org.junit.jupiter.api.Test;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

class OnErrorContinueTest {
    @Test
    void testOnErrorContinue() {
        Flux.range(1, 3)
                .doOnNext(n -> System.out.println("Main-1: " + n))
                .flatMap(this::processElement)
                .doOnNext(n -> System.out.println("Main-2: " + n)) // Why does onErrorContinue recovers that line, if it is after?
                .onErrorContinue((ex, o) -> System.err.println("    Error processing " + o + " - " + ex.getMessage()))
                .doOnNext(n -> System.out.println("Main-3: " + n))
                .subscribe();
    }

    @Test
    void testOnErrorResume() {
        Flux.range(1, 3)
                .doOnNext(n -> System.out.println("Main-1: " + n))
                .flatMap(n -> this.processElement(n)
                        .doOnError(ex -> System.err.println("    Error processing " + n + " - " + ex.getMessage()))
                        .onErrorResume(e -> Mono.empty()))
                .doOnNext(n -> System.out.println("Main-2: " + n))
                .subscribe();
    }

    Mono<Integer> processElement(Integer i) {
        return Mono.just(i)
                .doOnNext(n -> System.out.println("    Process-1: " + n))
                .doOnNext(n -> {
                    if (n == 2) {
                        throw new RuntimeException("Forcing exception for " + n);
                    }
                })
                .doOnNext(n -> System.out.println("    Process-2: " + n))
                .thenReturn(i) // Why does onErrorContinue recovers everything after that line?
                .doOnNext(n -> System.out.println("    Process-3: " + n))
                ;
    }
}

testOnErrorResume() produces exactly what I would expect:

Main-1: 1
    Process-1: 1
    Process-2: 1
    Process-3: 1
Main-2: 1
Main-1: 2
    Process-1: 2
    Error while processing 2 - Forcing exception for 2
Main-1: 3
    Process-1: 3
    Process-2: 3
    Process-3: 3
Main-2: 3

However, testOnErrorContinue() produces:

Main-1: 1
    Process-1: 1
    Process-2: 1
    Process-3: 1
Main-2: 1
Main-3: 1
Main-1: 2
    Process-1: 2
    Error while processing 2 - Forcing exception for 2
    Process-3: 2     -- UNEXPECTED - WHY IS THIS PRINTED?
Main-2: 2            -- UNEXPECTED - WHY IS THIS PRINTED?
Main-3: 2
Main-1: 3
    Process-1: 3
    Process-2: 3
    Process-3: 3
Main-2: 3
Main-3: 3

My doubts:

  1. Why does onErrorContinue() recover inside the processElement() method? It seems like thenReturn() has something to do with it, but cannot understand how, because the thenReturn()s documentation states

    On an error in the original Mono, the error signal is propagated instead.

  2. Why does onErrorContinue() recover before it is called? Why is the code System.out.println("Main-2: " + n) executed?

Mark Rotteveel
  • 100,966
  • 191
  • 140
  • 197
Honza Zidek
  • 9,204
  • 4
  • 72
  • 118

0 Answers0