Home > Blockchain >  Blocking calls on WebClient hangs indefinitely
Blocking calls on WebClient hangs indefinitely

Time:03-16

I have three WebClients that look something like this:

WebClient

public Mono<MyObject> getResponseOne() {
    return webClient.get()
        .uri(URI) 
         .header("header", header)
        .bodyValue(body)
        .retrieve()
        .bodyToMono(MyObject.class);
}

Then I have a controller which calls multiple WebClients:

Controller

@ResponseBody
@PostMapping("/get")
public Mono<MyObject> processResponse() {
    MyObject obj = getResponseOne().toFuture().get();
    system.out.println("Got first response");

    String str = getResponseTwo().toFuture().get();
    system.out.println("Got second response");

    //process and send with third WebClient
    MyObject newObj = getResponseThree(obj, str).toFuture().get();

    //process response from third WebClient and send to fourth WebClient
    //return statement

}

When I call /get, the console only prints "Got first response" then it just stops there and anything below doesn't seem to be executing. I'm using Postman to send the request, so it keeps on waiting without getting any response.

This may or may not be relevant, but I'm using blocking calls because I need the both responses to be processed before sending it to a third WebClient, the response from the third WebClient will also go through additional processing before being returned as the response of processResponse().

Solution

I used Mono.zip() like Alex suggested:

@ResponseBody
@PostMapping("/get")
public Mono<MyObject> processResponse() {
    //TupleN depends on the amount of Monos you want to process
    Mono<Tuple2<MyObject,String>> output = Mono.zip(getResponseOne(),getResponseTwo());

    return output.map(result ->{
        // getT1() & getT2() is automatically generated by the tuple
        MyObject obj = result.getT1();
        String str = result.getT2();
    
        getResponseThree(obj, str);

        //process and return
    });
}

More about Mono.zip()

CodePudding user response:

In reactive API nothing happens until you subscribe. Your method returns Mono and you need to construct a flow combining publishers. There are multiple ways to combine depending on the required logic.

For example, if you need the result of the predecessor you could use flatMap to resolve Mono sequentially

return getResponseOne()
    .flatMap(res -> getResponseTwo(res))
    .flatMap(res -> getResponseThree(res));

In case calls are independent you could use then

return getResponseOne()
    .then(getResponseTwo())
    .then(getResponseThree());

You could also execute in parallel using Mono.when(getResponseOne(), getResponseTwo(), getResponseThree()) or Mono.zip(getResponseOne(), getResponseTwo(), getResponseThree()).

There are many other operators but the key here is to construct the flow and return Mono or Flux.

  • Related