How to send HTTP requests in parallel

Viewed 343

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?

0 Answers
Related