0

Ill preface this by saying I am new at WebFlux and reactive programming in general and I am trying to get up to speed on the best patterns and practices.
But I am looking for a way to make many parallel api calls only after I successfully make another seperate API call.

Something like this

    Mono<someReturnObject> saveStateOfMultipleObjectsinTheDB(SO request){
      Mono<String> 1stCallResult = saveFirstObject(request.getFirstObject());
      Mono.zip(saveSecondObject(request.getSecondObject().subscribeOn(Schedulers.elastic()), saveThirdObject(request.getThirdObject().subscribeOn(Schedulers.elastic())).map(this::maptoSomeReturnObject())
    }

Now that is a slight simplification. Ideally I would like to write a lambda function in each of those zip methods, but if I have to I will write up a function just like described here. But is my thinking right with this pattern?

SoftwareSavant
  • 9,467
  • 27
  • 121
  • 195
  • no its not, `onSubscribe` means that when someone subscribes to this chain, the entire chain will be placed on a specific scheduler. So by having multiple of them wont place them on separate schedulers. Only one will be taken into account. Also, if you wish to save stuff after the first, you need to chain on the first with for instance flatMap or doOnSuccess or the likes, otherwise you will be breaking the chain. I would recommend that you post either your actual code, or a small working example that shows your intent, that is runnable. The code you have provided does not compile. – Toerktumlare Jul 02 '21 at 00:04
  • So those are not onSubscribes ... they are subscribeOn with an associated scheduler to tell the compiler I want each on a separate thread. From this Baeldung article : https://www.baeldung.com/spring-webclient-simultaneous-calls 'It specifies what kind of Scheduler to use when the subscribe call happens' Both flatMap and doOnSuccess occured to me, I did hope their was a more elegant solution. I guess I should have mocked each of the above methods and classes I referenced. Feedback noted. – SoftwareSavant Jul 02 '21 at 13:06
  • i ofc meant `subscribeOn` it was late and i would instead read the official reactor documentation https://projectreactor.io/docs/core/release/reference/#_the_subscribeon_method and not Baeldung articles, which states the following: `subscribeOn applies to the subscription process, when that backward chain is constructed. As a consequence, no matter where you place the subscribeOn in the chain, it always affects the context of the source emission.`and also `Only the earliest subscribeOn call in the chain is actually taken into account.` – Toerktumlare Jul 02 '21 at 14:40
  • so placing 1, 2 or 5 `subscribeOn` does not matter, only the first one will be used for the entire chain. Second of all parallel api calls wont give better performance, because most often calls to external services are about not blocking. You make a call to a service, and webflux will, instead of waiting for the response for that call, leave and use the same thread to make another call. It does this by using the for instance the `flatMap` operator. – Toerktumlare Jul 02 '21 at 14:45
  • Parallel work is many times only beneficial if you have computational heavy work, like heavy calculations that you need to place out on multiple CPU cores, using the cores to do the heavy lifting. Im guessing you want async work. But making multiple calls to eternal services, are often more about orchestration, making an I/O call is not computationally heavy. Thats why i was asking for what your actual user case is with some code that actually is compilable so that we can more understand what it is you are going for and give you a good answer. – Toerktumlare Jul 02 '21 at 14:47
  • So the code isn't written yet. I am mulling over designs. And that is what I was thinking of. I need to make multiple API calls. The first one is important and the information from it is needed to make subsequent API calls. But the subsequent API calls, could all theoretically execute in parallel. Like with a mono.zip (from what I understand ... Again, I am newish to WebFlux so I am still wrapping my mind around these constructs ... Not an excuse just my reality.) – SoftwareSavant Jul 02 '21 at 15:33
  • Also looks like I was looking for the .runOn(Schedulers.parallel()) method and not subscribe on. Good eye. – SoftwareSavant Jul 02 '21 at 15:36
  • But as i said, you wont be needing parallel, you will most likely need to do things in a `flatMap`. flatMap will do your requests for you async, just so you dont have to deal with parallel schedulers etc. Using parallel in this scenario is probably just a waste of resource and could potentially be worse performane than flatmap – Toerktumlare Jul 02 '21 at 16:55
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/234456/discussion-between-softwaresavant-and-toerktumlare). – SoftwareSavant Jul 02 '21 at 18:49

1 Answers1

2

You are on the right track, you just need to use then operator to chain the two concurrent calls after the first one. Also, as discussed in the comments subscribeOn is unnecessary if you use a reactive client (like WebClient) under the hood.

Mono<SomeReturnObject> saveStateOfMultipleObjectsinTheDB(SO request) {
    return saveFirstObject(request.getFirstObject())
        .then(Mono.zip(
            saveSecondObject(request.getSecondObject()),
            saveThirdObject(request.getThirdObject()))) 
        .map(this::maptoSomeReturnObject);
}
Martin Tarjányi
  • 8,863
  • 2
  • 31
  • 49
  • What if I need a value out of the return result of the saveFirsObject ... In my case, it is returning a Mono – SoftwareSavant Jul 03 '21 at 18:02
  • When I flatMap I take the result of the api call and then I set up the next object that I need to make consecutive calls in the Mono.zip However, I can't get the return result out of Mono.zip(...).map() – SoftwareSavant Jul 03 '21 at 18:22
  • 1
    So you need the result of the first and the two concurrent calls to create final result, right? – Martin Tarjányi Jul 03 '21 at 20:32
  • Correct. And I actually need the final result as a json body to pass back to any clients calling this ... It is a webflux api. – SoftwareSavant Jul 04 '21 at 04:43
  • https://stackoverflow.com/questions/68232599/spring-webflux-returning-null-back-to-controller - the code you have in this other question seems to fit your purpose, the first result is available in the map method – Martin Tarjányi Jul 04 '21 at 07:17