May I ask how to send HTTP requests in parallel in the context of Spring Webflux and Spring WebClient?
I have a very simple scenario, where from one request, step 1, I make a first request to one external API.
Step 2, from the result of the first request from step 1, I have to make N (let's say three requests in parallel to external APIs)
Since for Step 2, they have no dependencies on each other, I would like this to be done in parallel.
However, I do need to "wait" for the result of everyone, so that I can do a last step computation.
How to achieve this in Spring Webflux Spring WebClient please?
I wrote the following, and contacted each and every external party I am sending the request to.
@RestController
public class QuestionController {
private WebClient webClient;
@Autowired
public QuestionController(WebClient webClient) {
this.webClient = WebClient.create("http://some-service:8111/getPriceForFoo");
}
@GetMapping("/question")
public Mono<String> question(@RequestParam(value = "foo", required = false) String foo) {
//Step 1 - get the price through an API to some service
Mono<String> priceMustBeComputedFirst = firstComputePriceBySendingRequest(foo).cache();
// this step can be computed in parallel with companyB and companyC
Mono<String> interestToBuyFromCompanyA = areYouInterestedToBuyCompanyA(priceMustBeComputedFirst);
// this step can be computed in parallel with companyA and companyC
Mono<String> interestToBuyFromCompanyB = areYouInterestedToBuyCompanyB(priceMustBeComputedFirst);
// this step can be computed in parallel with companyA and companyB
Mono<String> interestToBuyFromCompanyC = areYouInterestedToBuyCompanyC(priceMustBeComputedFirst);
return Mono.zip(interestToBuyFromCompanyA, interestToBuyFromCompanyB, interestToBuyFromCompanyC).map(tuple3 -> computeSomethingAtTheEnd(tuple3.getT1(), tuple3.getT2(), tuple3.getT3()));
}
private Mono<String> firstComputePriceBySendingRequest(String foo) {
return webClient.mutate().baseUrl("http://some-service:8111/getPriceForFoo").build().get().uri("/{foo}", foo).retrieve().bodyToMono(String.class);
}
private Mono<String> areYouInterestedToBuyCompanyA(Mono<String> priceMustBeComputedFirst) {
return priceMustBeComputedFirst.flatMap(product -> webClient.mutate().baseUrl("http://companyA/areYouInterestedToBuy").build().get().uri("/{product}", product).retrieve().bodyToMono(String.class));
}
private Mono<String> areYouInterestedToBuyCompanyB(Mono<String> priceMustBeComputedFirst) {
return priceMustBeComputedFirst.flatMap(product -> webClient.mutate().baseUrl("http://companyB/areYouInterestedToBuy").build().get().uri("/{product}", product).retrieve().bodyToMono(String.class));
}
private Mono<String> areYouInterestedToBuyCompanyC(Mono<String> priceMustBeComputedFirst) {
return priceMustBeComputedFirst.flatMap(product -> webClient.mutate().baseUrl("http://companyC/areYouInterestedToBuy").build().get().uri("/{product}", product).retrieve().bodyToMono(String.class));
}
private String computeSomethingAtTheEnd(String t1, String t2, String t3) {
return "some computation based on each company s response";
}
}
For some reason, it seems what I am currently doing is sequential. I got the timestamps from each company, and indeed, company A receives the request before company B. Company B received before company C, etc etc etc, I believe it is very sequential.
I also added logs on my end, and it seems it is also sequential.
Is this code indeed sequential?
Is it because of the Mono.zip?
How to achieve this parallelism, please?