Calling Multiple apis synchronously, spring boot webflux - spring-boot

In my project we are using spring boot webflux, and I have this scenario where i have to call multiple api's from within a particular microservice synchronously.
e.g.
for(String api:apiNames){
//call api's
}
As per my understanding, webClient works asynchronously, until and unless someone subscribe to it it wont release the response.
in my current scenario i have to make use of webclient and I have to call each api only after successfull execution of previous api.
Note:- api response can be anything success/failure
Please help me in implementing this synchronous call

You can use the #block() method to make it synchronous.
Example on a mono (https://projectreactor.io/docs/core/release/api/reactor/core/publisher/Mono.html#block--)
For example on the (asynchronous) webflux webclient:
return webClient.get()
.uri(uri)
.accept(MediaType.APPLICATION_JSON)
.retrieve()
.bodyToMono(String.class)
.block();
The above example will wait with executing any next line of code untill it has received a response.
After which you can just make another call to another api in the same way.
Edit: As pointed out in the comments I would like to add a warning that using #block() is not efficient and you should try and chain more reactive calls and try to avoid making your application non reactive.
A nice post with more details can be found here: https://stackoverflow.com/a/57365926/1326867

Although, the question uses the word "synchronously", the description rather seems to suggest that sequentiality is what is needed, meaning executing each request one after the other.
If that's the requirement, it can be implemented the following way with Reactor:
Flux.fromIterable(apiNames)
.concatMap(apiName -> webClient...) // concatMap ensures sequential execution
However, if the application is a blocking Spring application, then Nick Hol's answer is also a correct one.

Related

Spring jaeger propagating span to an Async method

I have a simple Spring Boot 2.x RestController with an endpoint performing certain remote calls as well as controller is also calling an Async method that in turn makes several remote HTTP calls.
I'm having opentracing-spring-jaeger-web-starter in classpath with tracing enabled. If i invoke my REST endpoint, It creates a span for the endpoint call as well as remote calls that the controller is making synchronously.
However the remote calls made by Async method is getting reported in its own span. Is this by design or is there a way to propagate some context information to the Async method to better group/relate the spans ?
I solved it by using this library instead https://github.com/opentracing-contrib/java-spring-cloud
It seem to have an option to enable or disable different instrumentation feature. Read about opentracing.spring.cloud.async.enabled for more info.

How to make Spring Boot REST controller asynchronous?

My application is simple 3-tier Spring Boot rest web-service with usual synchronous endpoints.
But since the period of getting response from downstream system where my service sends requests is quite long (kind of 60 seconds), I need to add support of asynchronous REST calls to my service to save upstream systems from a response awaiting. In other words, if a response to a downstream system is going to take more than 60 seconds (timeout), then the upstream system break the connection with my service and keeps its doing...
But when the response come, my service using "reply-to" header from the upstream system will send the response to the upstream system.
All the things above are kind of call back or webhook.
But I didn't find any examples of implementation.
How to implement this mechanism?
How can I find more information?
Does Spring Boot have something to implement it out-of-box?
Thank you for attention!
You can use the #Async annotation from Spring. You will also need to enable in your application this by setting #EnableAsync.
An important note is that your method with the #Async annotation should be on a different class from where it is being called. This will let the Spring proxy intercept the call and effectively do it asynchronous.
Please find here the official tutorial.

What is the proper way to make an api call via springs `WebClient`, but ignore the result?

What is the proper way to make an api call via springs WebClient, but ignore the result? The ClientResponse object specifically calls out that I have to do something with the result...
Docs:
NOTE: When given access to a ClientResponse, through the WebClient exchange() method, you must always use one of the body or toEntity methods to ensure resources are released and avoid potential issues with HTTP connection pooling. You can use bodyToMono(Void.class) if no response content is expected. However keep in mind that if the response does have content, the connection will be closed and will not be placed back in the pool.
Can I make a WebClient call and ignore the results? or is there a generic catch all "body or toEntity method" that I can use and then ignore?
Prior to Spring Framework 5.2, using the WebClient#exchange() method and dealing directly with the Mono<ClientResponse> could be quite complex or lead to potential memory leaks.
As of Spring Framework 5.2, this has been made much easier for developers and the exchange() method has been deprecated.
Mono<ResponseEntity<Void>> response = webClient.put()
.uri("https://example.org/book/123")
.retrieve()
.toBodilessEntity();
Spring will read the response body (if present) and release the data buffers, and then return the connection to the pool. It's making sure that there's no memory leak, including when additional Reactor operators are used.

WebClient vs RestTemplate

As per spring 5:
WebClient is an interface representing the main entry point for performing web requests.
It has been created as a part of the Spring Web Reactive module and will be replacing the classic RestTemplate in these scenarios. The new client is a reactive, non-blocking solution that works over the HTTP/1.1 protocol
Does that mean, we need to recode for the old applications using RestTemplate if we want to upgrade to Spring 5?
Or there is some workaround to work with RestTemplate in Spring 5?
No, RestTemplate will continue to exist (at least for now). You don't have to replace it with WebClient.
One of the main differences is RestTemplate is synchronous and blocking i.e. when you do a rest call you need to wait till the response comes back to proceed further.
But WebClient is complete opposite of this. The caller need not wait till response comes back. Instead he will be notified when there is a response.
If you need such a functionality, then yes you need to replace your Resttemplate with WebClient.
You can in fact achieve Rest template like synchronous processing in webclient using .block(). But the other way is not possible.
EDIT:
RestTemplate will be deprecated in a future version(> 5.0) and will not have major new features added going forward
According to the Java Doc the RestTemplate will be in maintenance mode. Spring team advise to use the WebClient if possible:
NOTE: As of 5.0, the non-blocking, reactive
org.springframework.web.reactive.client.WebClient offers a modern
alternative to the RestTemplate with efficient support for both sync
and async, as well as streaming scenarios. The RestTemplate will be
deprecated in a future version and will not have major new features
added going forward.
RestTemplate is not really deprecated. But it will not be evolved in the future. So sticking to RestTemplate is perfectly valid if it does what you need.
Another way to put that is that if you need specific usage patterns like streaming, scatter/gatter, or custom timeouts, this won't be covered by RestTemplate and you need to use WebClient instead.
Now using WebClient in a blocking application is fine too. Using block() shouldn't hurt there and Spring MVC controller does partially support reactive return types.
WebClient is Non-Blocking Client, RestTemplate is Blocking Client.
For a long time, spring serves as a web customer. Under the hood, RestTemplate uses the Java API API, which is based on the subject model.This means that the matter will be blocked until the client receives a response. The problem with the blockage code is due to the existence of any string of memory and cpu cycles. Let us consider a lot of applications that are waiting for low services that are needed to produce the result.Sooner or later, requests for the results are collected. As a result, the program creates many issues, which result in depletion of a pool of thread or occupying all of the available memory. We can also experience performance performance due to the cpu switching.
Spring WebClient vs. RestTemplate
WebClient supports asynchronous as well as synchronous calls.
RestTemplate supports only synchronous calls.
No changes are required in old code even if the RestTemplate is depracated(as long as you don't need asynchronous behaviour)

How to consume a Reactive Spring Rest API with WebClient

I need to consume a reactive rest API (built with spring webflux) on a backend job (executable jar).
I've read about Spring WebClient, but I am not understanding some points.
For instance:
WebClient webClient = WebClient.create("http://localhost:8080");
Mono<Person> person = webClient.get()
.uri("/persons/{id}", 42)
.accept(MediaType.APPLICATION_JSON)
.exchange()
.then(response -> response.bodyToMono(Person.class));
On the last line, there is a "bodyToMono". So that's my question:
If the Rest API being called is already a reactive service, do I need to transform the response to a mono? Is there some point I'm missing?
From my perspective, I think could have a way to let explicit in the code that my Rest API is reactive, but probably is something I am not aware about.
Yes it is required.
The whole idea of being reactive is to make sure none of the Thread are blocked for IO.
You may have made your server side service reactive, but when your consuming that what is the benefit you get when your client is blocked untill there is a response from server. Your client thread keeps waiting untill the server responds. Which is not desired.
webClient.get()
.uri("/persons/{id}", 42)
.accept(MediaType.APPLICATION_JSON)
.exchange().block()
will block your current client thread to wait till the server responds. This can block your client thread.
webClient.get()
.uri("/persons/{id}", 42)
.accept(MediaType.APPLICATION_JSON)
.exchange()
.then(response -> response.bodyToMono(Person.class));
Gives you a Mono which is a reference to a publisher that can emit a single value in future. So the client thread is non blocked.
I have blogged explaining this more.
https://dzone.com/articles/spring-5-reactive-web-services

Resources