I use Spring boot #scheduled to execute a task periodically. I want to redirect and jump to another page after the periodic execution of the task is completed. However, the process is executed periodically and the message is displayed, but the redirect is not performed.
Please advise me.
enter code here
#Controller
#RequestMapping("/index")
public class TaskController {
#Scheduled(fixedRate = 5000)
public String task(){
System.out.println("test");
return "redirect:/index";
}
}
A method annotated with scheduled is running in your application without any interaction from the outside. So there is no client that could be redirected to anything.
You can only redirect from a method that is called because it is an mapped to a get or put or any other kind of request.
Related
I have an API endpoint /api1 that will make 2 service calls -
insertIndb(), called on certain inputs
verify(), called on certain inputs
I want to return the response of insertIndb() to the caller when they call /api1 only and not the verify() call. The verify() call if called, the caller need not wait for the response of this call but just get something like response in process. Since the goal of verify() is to update db and not return back anything.
So I was suggested to make this verify call in background. How can I do that?
Summarizing my flow below:
Enduser send POST /api1 with payload entity.
If entity does not exist,
the /api1 will make a insertIndb() call and return the response to the end user as 200.
After this, It will call /verify in background, the enduser need not wait for the response. // How to do this?
If entity exists,
It will only call /verify in background, the enduser need not wait for the response. // How to do this?
Probably return just 200 on your request is submitted.
How to run the above /verify calls in background based on the above flow is my question. Could anyone please help me here?
There are multiple ways to may a non-blocking fire-and-forget call like this.
The simplest, IMO, is to use a separate thread to execute the call using a synchronous operation. Another is to use tooling that supports non-blocking calls.
In addition, there are frameworks that simplify this effort. Camel comes to mind. Of course, there is a fair amount of effort to use the framework itself.
You can achieve this by using #EnableAsync annotation in spring by following way:
#SpringBootApplication
#EnableAsync
public class MyApplication {
public static void main(String[] arg) {
SpringApplication.run(MyApplication.class);
}
}
then you need to mark the emailUserInTheBackground method with #Async annotation.
#Service
class AnotherService {
#Async
public void verify(int userId) {
try {
TimeUnit.SECONDS.sleep(10);
System.out.println("Print from async: "+ Thread.currentThread().getName());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
Now add one more logger after a method call, you'll see getUsers(...) call completing first in a different thread even though the emailService thread is blocked for 10 seconds.
anotherService.verify();
System.out.println("Print from service: "+ Thread.currentThread().getName());
Also, there is CompletableFuture for achieving non blocking coding . You can read more about this in below link
https://www.javatpoint.com/completablefuture-in-java
I am writing a service where I want to expose an endpoint which will call another service and if the service call is successful then I want to send back the result to UI/ calling app.
In parallel before sending back the response, I want to execute/submit a task which should run in background and my call should not be dependent on success or failure of this task.
Before returning the response i want to do the-
executorService.execute(object);
This should not be a blocking call..
Any suggestion
Spring Async methods is the way to go here as was suggested in comments.
Some caveats:
Async methods can have different return types, its true that they can return CompletableFuture but this is in case if you called them from some background process and would like to wait/check for their execution status or perhaps, execute something else when the future is ready. In your case it seems that you want "fire-and-forget" behavior. So you should use void return type for your #Async annotated method.
Make sure that you place #EnableAsync. Under that hood it works in a way that it wraps the bean that has #Async methods with some sort of proxy, so the proxy is actually injected into your service. So #EnableAsync turns on this proxy generation mechanism. You can verify that this is the case usually in the debugger and checking the actual type of the injected reference object.
Consider customizing the the task executor to make sure that you're running the async methods with executor that matches your needs. For example, you won't probably want that every invocation of async method would spawn a new thread (and there is an executor that behaves like this). You can read about various executors here for example
Update
Code-wise you should do something like this:
public class MyAsyncHandler {
#Async
public void doAsyncJob(...) {
...
}
}
#Service
public class MyService {
#Autowired // or autowired constructor
private MyAsyncHandler asyncHandler;
public Result doMyMainJob(params) {
dao.saveInDB();
// do other synchronous stuff
Result res = prepareResult();
asyncHandler.doAsyncJob(); // this returns immediately
return res;
}
}
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.
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
I'm writing a web application which offers image files upload.
After the file's uploaded (using JavaScript) the user needs to submit a form.
After submitting, image files are processed (making thumbnails and so on ), that's why I wanted to pass the HttpServletRequest to an #Async service.
Unfortunately when I use #Async my application doesn't insert anything in the database. There is no error also. It's just not happening.
When I remove #Async, it works fine, but the form submission takes a long time.
I also use #EnableAsync after #Service.
What is wrong ?
#ResponseBody
public String addAdvertisement(Model model, HttpServletRequest request){
addAdvertisementService.addAdvertisement(request);
return "OK";
}
AND ASYNC SERVICE
#Service
#EnableAsync
public class AddAdvertisementService {
public String addAdvertisement(HttpServletRequest request){
...
System.out.println(" REQUEST " );
int customerId = customerNotRegisteredService.addCustomer("", ipAddress, email, phoneNumber);
REQUEST is displayed on the console, but "addCustomer" is not invoked...
This could be due to scoped nature of request object.
With #Async you are processing it in a different thread. So servlet thread is free and your request is complete.
To do is properly either clone your request and pass cloned object or you can use Future object and block main thread.
Cloning HTTP request and response is possible via HttpServletResponseWrapper class http://docs.oracle.com/javaee/1.3/api/javax/servlet/http/HttpServletResponseWrapper.html.