Spring Non-blocking Rest "Send and forget" - java

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

Related

Async on spring boot rest rest api - annotation should be on service only or controller

I have to implement a method with async features in spring boot:
I am a bit confused regarding the location of the annotation asyn, basically my rest controller is as follows:
#RestController
#RequestMapping("/email")
public class EmailController {
public #ResponseBody ResponseEntity<String> sendMailCon(#RequestBody EmailRequestDto emailRequestDto) {
LOG.debug("calling method sendMail from controller ");
//do complex stuff
sendMailService.sendEmail(emailRequestDto);
return new ResponseEntity<>("Mail has been sent successfully", HttpStatus.OK);
}
And service class is as follows:
#Component
public class SendMailServiceImpl implements SendMailService {
private static final Logger LOG = LoggerFactory.getLogger(SendMailServiceImpl.class);
#Autowired
private JavaMailSender javaMailSender;
#Override
#Async("threadPoolExecutor")
public void sendEmail(EmailRequestDto emailRequestDto) {
LOG.debug("calling method sendMail do complex stuff");
...
}
I have configured my async bean as follows:
#EnableAsync
#Configuration
public class AsyncConfig {
#Bean(name = "threadPoolExecutor")
public Executor getAsyncExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(10);
executor.setMaxPoolSize(25);
executor.setQueueCapacity(100);
executor.initialize();
return executor;
}
My question is the annotation #Async on the SendMailServiceImpl is correct or i need to add it on the method sendMailCon from controller?
Basically #Async will make method execute in a separate thread i.e. the caller will not wait for the completion of the called method.Each request to the server is served by a separate thread already , so you have no need to provide #Async on the controller method.
You could keep it in the service layer or better yet another layer down where you actually need the method to be executed asynchronously.In your case you could actually keep the method as async where you use rest template to trigger the mail.If you don't have another class for that it's okay to keep the service layer method as Async.
Read
Your implementation is correct. In this case you don't need to add #Async on the controller method
You code is correct and #Async makes your service code to execute in separate thread so controller becomes free immediately after calling the service. It works fine when you don't need to return a response from your execution. But if you need to process the request asynchronously and then collect the response to send back to the caller as REST response then you can use WebAsyncTask with Spring. Please refer below URL which explains the implementation of async REST service.
https://www.thetechnojournals.com/2019/10/asynchronous-rest-service.html

SpringBoot: Control Async behaviour from #RequestMapping analogous to an AsyncWebServlet?

I am working with Spring Boot 2 and I would like my requests to be handled asynchronously.
In Java EE, one can use Asynchronous Processing for Asynchronous Servlets as in this link. The following is a related example:
#WebServlet(urlPatterns={"/asyncservlet"}, asyncSupported=true)
public class AsyncServlet extends HttpServlet { ... }
and the above allows to use AsyncContext.
But in Spring Boot, I have the following #RequestMapping. How do I make it handle requests in Asynchronous mode and also supporting AsyncContext? How do I leverage the use of an Asynchronous Web Servlet?
#RestController
public class myRestController {
#RequestMapping("{resource}/**")
public void resourceRequest (#PathVariable("resource") String resource) {
// example:
// ... some long running calls such as database communication
// ... convert request through AsyncContext ctx = req.startAsync();
// etc
}
}
Note that returning void is intentional.
I found the following SO answer How to register a servlet with enabled "async-supported" in Spring-Boot? saying that "Spring Boot will automatically register any Servlet beans in your application context with the servlet container. By default async supported is set to true so there's nothing for you to do beyond creating a bean for your Servlet." but I am not using any #WebServlet annotations anywhere in my program, just the #RestController annotation. So how do I ensure that I am benefitting from asyncSupported option?

Invoke Spring Controller from Spring Integration flow

Hi I have a little problem. I want to invoke spring controller manually but I have an exception. Firstly, let me show you some integration flow and controller:
#Bean
public IntegrationFlow flow() {
return IntegrationFlows.from(
Amqp.inboundAdapter(rabbitMqConfig.connectionFactory(), queue)
.acknowledgeMode(AcknowledgeMode.MANUAL)
.errorChannel("errorChannel")
.concurrentConsumers(2)
.maxConcurrentConsumers(3))
.transform(Transformers.fromJson(Event.class))
.transform(new EventToRequestTransformer())
.handle(Request.class, (request, headers) -> controller.trigger(request))
.<ResponseEntity, HttpStatus>transform(ResponseEntity::getStatusCode)
.routeToRecipients(some routing)
.get();
}
#Controller
public class SomeController {
#RequestMapping(value = "/trigger", method = RequestMethod.POST)
public ResponseEntity<Response> trigger(#RequestBody Request request)
{
//some logic
}
}
When I'm running my app and sending an event I am getting exception on line:
.handle(Request.class, (request, headers) -> controller.trigger(request))
Exception:
nested exception is java.lang.IllegalStateException: No thread-bound request found: Are you referring to request attributes outside of an actual web request, or processing a request outside of the originally receiving thread? If you are actually operating within a web request and still receive this message, your code is probably running outside of DispatcherServlet/DispatcherPortlet
Could someone please tell me what is wrong and how to fix that? I thought I can just invoke controller method like it was coming from simple POJO.
You are mixing concerns and try to call Web tier from the service layer.
If the logic is like that, then design of the app is wrong.
You should extract some service from the controller logic and call it from the Web, as well as from there on the Integration level.
According your stack trace it looks like you try to get access to the request scope object. Well, and that is exactly what happens to #Controller beans, I guess.

How to make sure every API calls are served (Queueing Rest API calls)?

I am developing a REST API in Spring Boot which I am providing the response within mostly 1-3 sec.My Controller is like below:
#RestController
public class ApiController {
List<ApiObject> apiDataList;
#RequestMapping(value="/data",produces={MediaType.APPLICATION_JSON_VALUE},method=RequestMethod.GET)
public ResponseEntity<List<ApiObject>> getData(){
List<ApiObject> apiDataList=getApiData();
return new ResponseEntity<List<ApiObject>>(apiDataList,HttpStatus.OK);
}
#ResponseBody
public List<ApiObject> getApiData(){
List<ApiObject> apiDataList3=new List<ApiObject> ();
//do the processing
return apiDataList3;
}
}
So I have a 300 users concurrently loading the API.I performed the load test with JMeter and it was ok.But still there were some failures(not all API calls were served).So how do I overcome this?How to imlement any queue on the API calls which arrives or any other methods to ensure each API call is responded with data?
Do you mean that you would like to make sure all the requests return the data?! If yes, you can use #Async and get the CompletableFuture. Then in your Controller, you can use the CompletableFuture to get the response. In case there are some failure, you can set the timeout for that and catch the exception to log the error.
Hope this help.

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

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

Categories