1

Small question about the webflux reactive repository, especially about the methods saveAll Flux saveAll(Iterable var1); versus Flux saveAll(Publisher var1);

Wanted to compare, I wrote the following:

@Controller
@SpringBootApplication
public class Application {

    public static void main(String[] args) {
        SpringApplication.run(Application.class);
    }

    @Autowired
    private SomeReactiveRepository someReactiveRepository;

    @PostMapping(path = "/saveListInsideMono", consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
    public Mono<QuestionResponse> saveListInsideMono(@RequestBody Mono<QuestionRequest> questionRequestMono) {
        //just doing some business transformation on the list inside the mono
        Mono<List<String>> enhancedStringListMono = questionRequestMono.map(questionRequest -> enhance(questionRequest));
        //take the pojo inside the mono and map it to a saveAllAndConvertToResponse method (see next method)
        Mono<QuestionResponse> questionResponseMono = enhancedStringListMono.map(enhancedStringList -> saveAllAndConvertToResponse(enhancedStringList));
        return questionResponseMono;
    }

    private QuestionResponse saveAllAndConvertToResponse(List<String> enhancedStringList) {
        // use the repository <S extends T> Flux<S> saveAll(Iterable<S> var1); + subscribe
        return someReactiveRepository.saveAll(enhancedStringList).thenReturn(new QuestionResponse(enhancedStringList));
    //this also works but not good to subscribe
        //someReactiveRepository.saveAll(enhancedStringList).subscribe();
        //return new QuestionResponse(enhancedStringList);
    }

    @PostMapping(path = "/saveFlux", consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
    public Mono<QuestionResponse> saveFlux(@RequestBody Mono<QuestionRequest> questionRequestMono) {
        //just doing some business transformation on the list inside the mono
        Mono<List<String>> enhancedStringListMono = questionRequestMono.map(questionRequest -> enhance(questionRequest));
        // use the repository <S extends T> Flux<S> saveAll(Publisher<S> var1); to save the flatMapMany + fromIterable directly
        Flux<String> enhancedStringFlux = someReactiveRepository.saveAll(enhancedStringListMono.flatMapMany(Flux::fromIterable));
        Mono<QuestionResponse> questionResponseMono = enhancedStringFlux.collectList().map(enhancedString -> convertToResponse(enhancedString));
        return questionResponseMono;
    }

    private QuestionResponse convertToResponse(List<String> enhancedStringList) {
        //return the object needed
        return new QuestionResponse(enhancedStringList);
    }

    private static List<String> enhance(QuestionRequest questionRequest) {
        //dummy business transformation logic
        List<String> baseList = questionRequest.getList();
        List<String> enhancedList = baseList.stream().map(oneString -> "enhanced" + oneString).collect(Collectors.toList());
        return enhancedList;
    }

    public class QuestionRequest {
        private List<String> list;

        public List<String> getList() {
            return list;
        }
    }

    public class QuestionResponse {
        private List<String> enhancedList;

        public QuestionResponse(List<String> enhancedList) {
            this.enhancedList = enhancedList;
        }
    }

}

In terms of "correctness" both codes are doing what is expected. Everything is persisted successfully.

But in terms of performance, reactive paradigm, IO Utilisations to DB, Netty Core usage, what is the "best" solution and why please?

Thank you

PatPanda
  • 3,644
  • 9
  • 58
  • 154
  • dont subscribe, the consumer is the subscriber (in this case the calling client). `return someReactiveRepository.saveAll(enhancedStringList).thenReturn(new QuestionResponse(enhancedStringList));` – Toerktumlare Sep 01 '20 at 14:26
  • Does this answer your question? [Mono> difference with Flux in Spring webflux](https://stackoverflow.com/questions/52927137/monolistt-difference-with-fluxt-in-spring-webflux) – K.Nicholas Sep 01 '20 at 18:11
  • @ThomasAndolfquestion updated, thanks. I would like to just emphasize the purpose of the question, which is the pros and cons of one versus the other. I mean, I can keep optimizing each of them independently like I just did for the first /saveListInsideMono, but really the comparison is what I would like to understand. Thank you – PatPanda Sep 01 '20 at 20:30
  • Hello @K.Nicholas, sadly, not really. I read the whole page and got some more insight on a general Mono vs Flux, But this use case really deals with reactive repository and performance on whole processing – PatPanda Sep 01 '20 at 20:32
  • @PatPatPat - Really it's the same question. A `Mono` is a single object in the pipeline and a `Flux` is multiple objects in the pipeline. It is not clear to me how backpressure would work, if at all, with a `Mono` and the amount of data involved is central to your question. This question could also be closed as being too broad. You can find more information at https://projectreactor.io/docs/core/release/reference/ – K.Nicholas Sep 01 '20 at 22:09
  • I do not think this question is too broad or is directly related to the link you suggested @K.Nicholas. Got some more interesting feedback offline that there might be performance impact. While saving the Flux, the usual logs is something like: INFO [,27d6a91f83934629,27d6a91f83934629,true] 10874 --- [ctor-http-nio-3] But on the save, 10874 --- [ s1-io-0] this comes up. Maybe the save is not using the initial Core? I am looking for response more concrete like such. Thank you – PatPanda Sep 01 '20 at 23:36
  • While with the saveAll of the list, only logs with: [http-nio-X] are seen. But with the saveAll of the Flux, the saveAll is seen with [s1-io-X]. If this is expected, what does it means? Which one will hurt the reactive paradigm? – PatPanda Sep 01 '20 at 23:40
  • @PatPatPat - that's probably a vender specific paradigm. If you have working code you should probably post it. – K.Nicholas Sep 02 '20 at 03:30

1 Answers1

1

It all depends on what objects you currently have. If you have a Flux of objects, use the saveAll method that takes a Publisher. If you have the actual Collection of objects, use the saveAll method that takes an Iterable.

As an example, if you look at the implementation SimpleReactiveCassandraRepository the implementation of saveAll that takes an Iterable just wraps it in a Flux and delegates to the saveAll method that accepts a Flux

public <S extends T> Flux<S> saveAll(Iterable<S> entities) {

    Assert.notNull(entities, "The given Iterable of entities must not be null");

    return saveAll(Flux.fromIterable(entities));
}

As a result, there should no difference in terms of IO utilisation or netty core usage. Also, both follow the reactive paradigm.

SimpleReactiveCassandraRepository Code

Michael McFadyen
  • 2,675
  • 11
  • 25
  • Hello Michael, thank you for the comment, it gives me some assurance the two are interchangeable. While I saw the implementation of both are the same, my questions was also related to the case where there is a collection, but inside a mono. Shall we make it a Flux and saveAll Publisher, or extract the collection from within the mono and use saveAll Collection? – PatPanda Sep 02 '20 at 22:15
  • I would ask why you have a list on Monos instead of using a Flux? – Michael McFadyen Sep 02 '20 at 22:29
  • Sure. On the controller layer, it takes: @RequestBody Mono questionRequestMono. The QuestionRequest has bunch of fields, like some int ID, some String category, some long timestamp, bunch of others stuff (that are not collections). But it contains also a collection as part of the POJO, and the main business logic has to be done against this collection. The client/sender is a third party and cannot change how they send this. They cannot send a flux, or multiple QuestionRequest. They can only send one QuestionRequest object with the list inside – PatPanda Sep 02 '20 at 22:39
  • Hence my question if I may, what is the "best" way to save the list that is INSIDE QuestionRequest, particularly inside the Mono the client is sending? – PatPanda Sep 02 '20 at 22:42
  • I'm not sure I can really advise on that without seeing the exact code itself. – Michael McFadyen Sep 04 '20 at 20:54