Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mono.Defer() vs Mono.create() vs Mono.just()?

Tags:

Could someone help me to understand the difference between:

  • Mono.defer()
  • Mono.create()
  • Mono.just()

How to use it properly?

like image 715
Anton Tb Avatar asked May 13 '19 15:05

Anton Tb


People also ask

What is mono just ()?

The Mono. just method is the simplest method for Mono generation. It takes a single value and generates a finite Mono stream from it. A completion event is published after publishing the specified value: Mono.

What is the use of mono defer?

when you run Mono. just() it creates immediately an Observable(Mono)and reuses it but when you use defer it doesn't create it immediately it creates a new Observable in every subscribe. Your explanation is not totally right. There is nothing such as "create new Observable".

What is mono create?

Mono. create(monoSinkConsumer) is the most advanced method that gives you the full control over the emitted values. Instead of the need to return Mono instance from the callback (as in Mono. defer ), you get control over the MonoSink<T> that lets you emit values through MonoSink.

What is the difference between flux and Mono?

A Flux object represents a reactive sequence of 0.. N items, while a Mono object represents a single-value-or-empty (0..1) result. This distinction carries a bit of semantic information into the type, indicating the rough cardinality of the asynchronous processing.


2 Answers

Mono.just(value) is the most primitive - once you have a value you can wrap it into a Mono and subscribers down the line will get it.

Mono.defer(monoSupplier) lets you provide the whole expression that supplies the resulting Mono instance. The evaluation of this expression is deferred until somebody subscribes. Inside of this expression you can additionally use control structures like Mono.error(throwable) to signal an error condition (you cannot do this with Mono.just).

Mono.create(monoSinkConsumer) is the most advanced method that gives you the full control over the emitted values. Instead of the need to return Mono instance from the callback (as in Mono.defer), you get control over the MonoSink<T> that lets you emit values through MonoSink.success(), MonoSink.success(value), MonoSink.error(throwable) methods. Reactor documentation contains a few good examples of possible Mono.create use cases: link to doc.

The general advice is to use the least powerful abstraction to do the job: Mono.just -> Mono.defer -> Mono.create.

like image 76
Ilya Zinkovich Avatar answered Sep 19 '22 09:09

Ilya Zinkovich


Although in general I agree with (and praise) @IlyaZinkovich's answer, I would be careful with the advice

The general advice is to use the least powerful abstraction to do the job: Mono.just -> Mono.defer -> Mono.create.

In the reactive approach, especially if we are beginners, it's very easy to overlook which the "least powerful abstraction" actually is. I am not saying anything else than @IlyaZinkovich, just depicting one detailed aspect.

Here is one specific use case where the more powerful abstraction Mono.defer() is preferable over Mono.just() but which might not be visible at the first glance.

See also:

  • https://stackoverflow.com/a/54412779/2886891
  • https://stackoverflow.com/a/57877616/2886891

We use switchIfEmpty() as a subscription-time branching:

// First ask provider1
provider1.provide1(someData)
    // If provider1 did not provide the result, ask the fallback provider provider2
    .switchIfEmpty(provider2.provide2(someData))

public Mono<MyResponse> provide2(MyRequest someData) {
    // The Mono assembly is needed only in some corner cases
    // but in fact it is always happening
    return Mono.just(someData)
        // expensive data processing which might even fail in the assemble time
        .map(...)
        .map(...)
        ...
}

provider2.provide2() accepts someData only when provider1.provide1() does not return any result, and/or the method assembly of the Mono returned by provider2.provide2() is expensive and even fails when called on wrong data.

It this case defer() is preferable, even if it might not be obvious at the first glance:

provider1.provide1(someData)
    // ONLY IF provider1 did not provide the result, assemble another Mono with provider2.provide()
    .switchIfEmpty(Mono.defer(() -> provider2.provide2(someData)))
like image 27
Honza Zidek Avatar answered Sep 20 '22 09:09

Honza Zidek