Using Spring4 AsyncRestTemplate in a method which uses an #Async annotation - java

I am using the Spring4 AsyncRestTemplate to make calls to an External REST API service.
The method below is from a Spring #Service class. The AsyncRestTemplate is autowired from a Spring #Bean.
In the method, I register callbacks on the ListenableFuture response from the REST API call.
I don't use the returned ListenableFuture except for unit tests. The callbacks will handle the actual actions I want to take based on request success or failure.
ExternalServiceImpl.class
public ListenableFuture<ResponseEntity<ResponseBody>> makeExternalCall(RequestBody requestBody) {
HttpEntity<RequestBody> request = new HttpEntity<>(RequestBody, getDefaultHeaders());
ListenableFuture<ResponseEntity<ResponseBody>> responseEntity = asyncRestTemplate.exchange(serviceUri.toUriString(), HttpMethod.POST, request, ResponseBody.class);
responseEntity.addCallback(
(onSuccess) -> System.out.println("Success"),
(onFailure) -> onFailure.printStackTrace()
);
return responseEntity;
}
I plan on using the #EnableAsync annotation and setting up a ThreadPoolTaskExecutor as well as adding an #async annotation to the method in a manner similar to the procedure described here: Spring Asynchronous Methods
Questions
Is this redundant? Is there an additional benefit to scaling when
making the method async even though I'm using an
AsyncRestTemplate?
Is there anything considered best practice that I'm missing in
implementing this pattern?
Is there anything to watch out for?

#Async doesn't actually do anything until you add the #EnableAsync annotation to your application. When that happens, any code calling your makeExternalCall method will immediately return, and spring will look for a TaskExecutor bean to run the whole method asynchronously (rather than just your asyncRestTemplate service being the only async part of your code currently).
More info on the spring website: http://docs.spring.io/spring/docs/current/spring-framework-reference/html/scheduling.html

Related

How to add logging to a webflux endpoint in spring-mvc?

I have an existing spring-mvc application with different #RestController. Now I want to add a Mono<String> endpoint, and log the request timestamp with url path, as well as the response timestamp.
But how? I cannot simply #EnableWebFlux as I would have to disable spring-mvc therefor.
How could I register a filter explicit for the webflux endpoint that catches on invocation, and right before the response is written back async?
#RestController
public class FluxService {
#PostMapping
public Mono<String> post() {
return webClient.post().uri(uri).bodyValue(payload).retrieve().bodyToMono(String.class);
}
}
I want enhanced logging on the #PostMapping endpoint, not on the webClient!
MVC is a blocking/servlet based api, mixing it with webflux isn't going to work. They use different filters, security etc as MVC assumes a lot of ThreadLocal stuff. (Can I use SpringMvc and webflux together?)
If you really want to mix them like this you could use .doOnNext() once you get your mono and call your logger there.

Microservice feign infinite loop of invocations?

I am confused about how an infinite loop of feign calls might behave.
An example:
Assume I have 2 APIs, A & B.
if I call API A, which in turn calls API B via a feign HTTP call, which in turn calls API A again via feign, will it recognize this and break the call chain?
Quick flowchart of calls:
A -> B -> A -> B ... Repeat infinitely?
I have not tried this code, it is just an idea。
But I am assuming that spring-cloud-starter-feign will provide some methods to resolve this problem? Is this assumption correct?
#PostMapping(RestJsonPath.API_A)
ResponseEntity<byte[]> apiA();
#PostMapping(RestJsonPath.API_B)
ResponseEntity<byte[]> apiB();
Will it execute until it times out or hystrix will stop it?
TL;DR:
Feign will keep the connection open on the initial request from A to B until the pre-configured timeout kicks in. At this point, Feign will time out the request and if you have specified a Hystrix fallback, Spring will use your Hystrix fallback as the response.
Explanation:
spring-boot-starter-feign provides an abstraction layer for writing the HTTP request code. It will not handle potential loops or cycles in your code.
Here is an example spring boot feign client from their tutorials website for demonstration:
#FeignClient(value = "jplaceholder",
url = "https://jsonplaceholder.typicode.com/",
configuration = ClientConfiguration.class,
fallback = JSONPlaceHolderFallback.class)
public interface JSONPlaceHolderClient {
#RequestMapping(method = RequestMethod.GET, value = "/posts")
List<Post> getPosts();
#RequestMapping(method = RequestMethod.GET, value = "/posts/{postId}", produces = "application/json")
Post getPostById(#PathVariable("postId") Long postId);
}
Notice first that this is an interface - all the code is auto generated by Spring at startup time, and that code will make RESTful requests to the urls configured via the annotations. For instance, the 2nd request allows us to pass in a path variable, which Spring will ensure makes it on the URL path of the outbound request.
The important thing to stress here is that this interface is only responsible for the HTTP calls, not any potential loops. Logic using this interface (which I can inject to any other Spring Bean as I would any other Spring Bean), is up to you the developer.
Github repo where this example came from.
Spring Boot Docs on spring-boot-starter-openfeign.
Hope this helps you understand the purpose of the openfeign project, and helps you understand that it's up to you to deal with cycles and infinite loops in your application code.
As for Hystrix, that framework comes in to play (if it is enabled) only if one of these generated HTTP requests fails, whether it's a timeout, 4xx error, 5xx error, or a response deserialization error. You configure Hystrix, as a sensible default or fallback for when the HTTP request fails.
This is a decent tutorial on Hystrix.
Some points to call out is that a Hystrix fallback must implement your Feign client interface, and you must specify this class as your Hysterix fallback in the #FeignClient annotation. Spring and Hystrix will call your Hystrix class automatically if a Feign request fails.

Spring Non-blocking Rest "Send and forget"

I'm writing a non-blocking Spring Rest controller. My client should send a request and doesn't care for the response and doesn't need to wait.
This is my server code:
#RestController
#EnableAsync
public class testController {
#RequestMapping(value = "test", method = RequestMethod.GET)
public ResponseEntity<String> test() throws InterruptedException {
timeConsumingMethod();
System.out.println("I'm should be first");
return new ResponseEntity<String>("the server is processing your request", HttpStatus.OK);
}
#Async
private void timeConsumingMethod() throws InterruptedException {
Thread.sleep(1000*5);
System.out.println("I'm should be second!");
}
However, When I call http://localhost:8181/test using(POSTMAN, Chrome, etc...)
I get the following on the server log:
I'm should be second!
I'm should be first
AND only after waiting 5 seconds my browser shows:
the server is processing your request
Is that the correct way for a "send and forget" Behavior?
According to the doc page the #EnableAsync should be added on configuration class.
Enables Spring's asynchronous method execution capability, similar to
functionality found in Spring's XML namespace.
To be used on #Configuration classes as follows, where MyAsyncBean is
a user-defined type with one or more methods annotated with either
Spring's #Async annotation, the EJB 3.1 #javax.ejb.Asynchronous
annotation, or any custom annotation specified via the annotation()
attribute.
why don't you use this:
https://www.baeldung.com/spring-webclient-resttemplate
Webflux client seems to do the same. I was searching for a similar solution where 1 microservice calls multiple microservices async and this fits the model

Sending Email with spring in a new thread issue

One of the functionalities of app that I'm developing is that an email is sent every time user get's his invoice registered in our system. Sending an email from Java app easy especially if using Spring framework. I use JavaMailSenderImpl and SimpleMailMessage from Spring framework and it works okay.
But I need to send email in a new thread so that communication with SMTP server does not slow down the rest of apps processes. Problem is that when I call
MailSender.send()
method from a new thread, email message is not sent, as opposed when sending in a same thread.
I tried with spring's #Async annotation, spring Executor and plain old java.lang.Thread but it doesn't work.
Can email be send asynchronously in java with spring? Had anyone a similar issue with this?
I can post some code samples if needed.
Tnx
It should work.
You need to tell Spring that it should pay attention to your #Async Annotation by:
<task:annotation-driven />
And there are some limitations you need to pay respect to:
the annotated method must belong to a spring bean
the invocation of the annotated method must be executed from a different Spring Bean (if you are using standard Spring AOP).
1) Add task namespace into spring context. The following xsd is for Spring 3.0 release.
xmlns:task="http://www.springframework.org/schema/task"
http://www.springframework.org/schema/task
http://www.springframework.org/schema/task/spring-task-3.0.xsd
2) Declare the executor in your spring context file.
<!-- Executor for the methods marked wiht #async annotations -->
<task:executor id="asyncExecutor" pool-size="25" />
3) Configure this to Spring task
<!-- Configuration for the Runtime -->
<task:annotation-driven executor="asyncExecutor" />
These are all the configuration you need in the Spring context file.
The method you need to perform asynchronously annotate it with #Async annotaion.
Now, all the methods annotated with #async will be handled be spring task executor asynchronously.
One of the known issues of executing code in an asynchronous thread is that the exceptions thrown by that code are lost, unless you provide a specific handler to catch them. The effect you see (namely, the #Async method failing both to properly execute and to show a clue for that failure in the form of a log or stacktrace of some sort) is typically produced by such an exception, indeed thrown but swallowed by the asynchronous thread.
One of the many possible reasons why your #Async method works when synchronous is that you are doing some database operation from the method. It works when synchronous, because you are probably calling it from a #Transactional method of another #Service, so for that thread a Session or EntityManager is found; but it does not work when asynchronous, because in this case you are on a new thread, and if the #Async method is not #Transactional itself there is no Session or EntityManager that could perform the operation.
TL;DR Provide an exception handler to catch exceptions that would be swallowed by the asynchronous thread otherwise, or for the sake of debugging use a big try/catch for the body of the #Async method. You will probably see some exception popping up, then you will need to take the proper actions to avoid it.
You need to enable the feature in Spring:
#EnableAsync
public class MyApp {
public static void main(String[] args) {
SpringApplication.run(MyApp.class, args);
}
}

Providing a timeout value when using #Async for a method using Spring 3.0

I looked through the documentation but couldn't find if there is a way to specify a timeout for async operations spawned when using #Async annotated methods using Spring 3.0.
Is there a way to do that? I think this is pretty essential whenever making triggering an async computation.
Timeouts are not provided by the #Async annotation, since the timeout should be decided by the caller of the function, not the function itself.
I'm assuming you're referring to the timeout on an #Async-annotated method which returns a result. Such methods should return an instance of Future, and the get() method on Future is used to specify the timeout.
e.g.
#Async
public Future<String> doSomething() {
return new AsyncResult<String>("test");
}
and then
Future<String> futureResult = obj.doSomething(); // spring makes this an async call
String result = futureResult.get(1, TimeUnit.SECOND);
In #Async source code is no option for configuration.

Categories