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
.