Search code examples
spring-webfluxproject-reactor

Mono.then() vs .and() for parallelisation


I was previously saving an entity to table like so:
insertTableOne(foo).then(insertTableTwo(foo)).then(Mono.just(foo));

Team-member recommended using .and() to parallelise the inserts:
insertTableOne(foo).and(insertTableTwo(foo).thenRetuen(foo);

While I agree it looks cleaner, I cannot find any documentation that using .and() will execute both inserts at the same time. I thought it would still be sequential unless explicitly stated to be parallel with Schedulers.parallel().

Am I wrong?


Solution

  • The difference in the two examples are as followed.

    First you have to remember, everything here executed is done async. Meaning nothing is blocking. Something is fired off and the thread then goes and does something else until some form of response is returned.

    The then keyword is described as followed in the docs

    Let this Mono complete then play another Mono.

    Means it will fire off insertTableOne then when that is completed insertTableTwo.

    So yes they will be executed sequentially.

    If we look in the docs for the and keyword:

    Join the termination signals from this mono and another source into the returned void mono

    So what does this mean, well it means that when both Mono's terminate, for whatever reason we will return void. If first succedes other fails, or the opposite, or both fail, we dont care, both have to finish whatever they are doing, we then will return and continue.

    Yes this means that both will be fired of at the same time async see how im choosing my words here. NOT parallel im writing async.

    think of it this way, if we were parallel, it would be 2 people sending two emails. If we are async 1 person sends 2 mails, but really fast after each other. Also meaning, 2 seperate persons would process one email each, or in the async case, one person processing 2 email but really fast after each other.

    So in your case, it might be the same thread from a single scheduler scheduling both jobs for the event loop, or 2 seperate threads scheduling the work. It shouldnt matter, and you shouldn't care as it is up to the library to handle that.

    What you should care about is how you want to handle errors of failures, and() will continue no matter the outcome, so you have no idea if something failed or not.

    And to emphesise on your last statement:

    I thought it would still be sequential unless explicitly stated to be parallel

    Everything in webflux is async per default, and can be parallel if you explicitly state so. You can execute things async in sequence.

    An example:

    // This will execute n + 1 in sequence taking one item at the time 
    // preserving order and print 2,3,4
    Flux.just(1,2,3).map(n -> n + 1).subscribe(n -> System.out.println(n));
    
    // This will iterate through and execute n + 1 all at once, and 
    // order back is not guaranteed as the subscribe will print in 
    // order of what completed first, might be 2,3,4 might be 3,4,2 
    // or 2,4,3
    Flux.just(1,2,3).flatMap(n -> n + 1).subscribe(n -> System.out.println(n));
    

    The above example is theoretical but what i want to emphasis is that async is not paralellel but async can be sequential