I am using a Spring MVC controller and want to start the execution of a task in a new thread. However the task should not start immediately but only after the response has been sent to the client.
The sequence - in strict temporal order:
request
return new ResponseEntity ... / client receives HTTP status 200 OK.
processing of the task begins.
How do I achieve this?
I wanted to use Spring's async abstraction by calling a method annotated with #Async, but it does not guarantee that the new thread waits for the response to be sent first.
You can use an interceptor for that. The order of events for handling a request in Spring MVC is:
DispatcherServlet get a Request, Response pair and determines the handling
[optional] interceptors preHandle are called (with option to stop processing)
controller is called
[optional] interceptors postHandle are called
ViewResolver and view do the actual Response processing and send the response
[optional] interceptors afterCompletion are called
The above is over simplified and is just aimed at showing that interceptor afterCompletion methods are called after the response has been sent to client, with following signature :
void afterCompletion(HttpServletRequest request,
HttpServletResponse response,
Object handler,
Exception ex)
throws Exception
In that method, you can test the occurence of an exception and the correctness of the response (ex == null && response.getStatus() == HttpServletResponse.SC_OK) before starting your processing.
The HandlerInterceptor is the solution, but the code get a little bit more complex than expected.
Here's a code suggestion to make it simpler by putting the whole solution in a single class:
private static final ThreadLocal<Object> result = new ThreadLocal<Object>();
#RequestMapping("/mypath")
public Object execute() throws Exception {
Object obj = new Object();
result.set(obj); // Save the object to be used after response
return obj;
}
#Bean
public MappedInterceptor interceptor() {
return new MappedInterceptor(Arrays.array("/mypath"), new HandlerInterceptor() {
#Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
// Get the saved object
Object results = result.get();
// Clean for the next request
result.set(null);
// TODO Your code to be executed after response.
}
});
}
If your "after respond is sent" requirement is fulfilled with "after the view has been rendered" you may use an implementation of HandlerInterceptor. For an example cf. Spring 3 MVC Interceptor tutorial with example, triggering your job in afterCompletion.
If your job needs to be triggered "after it hit the wire", I'd like to know why.
You could add the task to a blocking queue, before the response entity is created. Let a task executor run periodically (every x seconds) over the queue and poll for tasks. If a task is found, it will be executed. If not, the thread finishes its run method and waits for the next run (in x seconds).
How to run a task periodically:
http://www.mkyong.com/java/how-to-run-a-task-periodically-in-java/
Inject the queue as dependency in both the controller and the task executor service. This should be an easy solution to start with.
In this szenario you can't be sure, that the client receives the request. But if you want to be safe(r), add a due date to your task object with a sufficient offset (e.g. current time + 30 seconds). Let the task executor check if the due date of the polled task is now or in the past. Otherwise ignore the task for this run.
Related
I am using log4j ThreadContext for tracing in a spring boot application. I have created an interceptor by implementing HandlerInterceptor which intercepts a request and then sets 'x' value in the ThreadContext map using ThreadContext.put("correlationId", 'x'). The value 'x' is retrieved from the request headers. After the request is completed I clear the ThreadContext using ThreadContext.clearMap(). The requirement is to see correlationId in the logs with every logger statement which is getting fulfilled.
public class RequestHandlerInterceptor implements HandlerInterceptor {
#Override
public boolean preHandle(
final HttpServletRequest request,
final HttpServletResponse response,
final Object handler)
throws Exception {
ThreadContext.put(CORRELATION_ID, request.getHeader(CORRELATION_ID_HEADER));
return true;
}
#Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, #Nullable Exception ex) throws Exception {
ThreadContext.clearMap();
}}
Now my question is what will be the behavior if multiple requests are made by multiple users simultaneously. Will the value of correlationId in ThreadContext map get replaced with every new request before the completion of older requests? If so, then what would be the correct implementation since if the values of correlationId is getting replaced before the request is completed then in the logs I would have incorrect correlationId logged.
Any help would be appreciated.
Are you working with blocking- or Non-blocking-IO (NIO)?
If you are working with blocking-IO (which probably most of the applications used the last decades), then your server will create a thread for every request made by a user. Everything from accepting the request, your business logic in your service classes and making calls to other systems like databases or services are handled by that request (and is blocked while waiting for answers from these system).
The ThreadContext is managed on a per thread basis and so separated from other threads and requests.
If you are working with NIO, then things start to get more complicated, because then a request made by an user is handled by several threads.
I have a controller that calls a webservice to start a batch job, when the result is returned, it should call another REST API based on this result. Then it should wait for the new result, and return this second result to user:
#RestController
public class LaunchController {
#PostMapping(path = "/launch", consumes = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<LaunchResult> launch(#Valid #RequestBody LaunchParams params) {
// in launch() I call the first REST API
LaunchResult result = myService.launch(params);
// here I need to call another REST API
AnotherResult result2 = callAnotherWebAPIBasedOnThisResult(result);
return ResponseEntity.ok(result2);
}
Now I want to know that is it good practice to do it like this (synchronously) and all in one controller ? Exist other way of doing this ?
Your controller is perfectly fine as it does not have any application logic inside and it actually calls the service methods. But It lacks the exception handling. You have catch with proper exceptions with try catch block or throws keyword.
The decision to convert the endpoint to an asychronous one depends on a few factors :
Is the batch job going to take time to be executed.
Can this process be converted to an asynchronous one.
Does the use case expect the user to wait until the action is completed.
If the your answer is yes, it's better to convert the endpoint to an ayschronous one and update the user with the details later after all processes including the batch processes are completed . It's always better NOT to keep the user waiting for a response. Non-blocking requests makes sense when you are dealing with a lot of data and processing needed for this data. Also, by making this request asynchronous you will have better control over the processing stages and provide the user with better statistics incase any of the processing stage resulted in failure. For instance the batch job could fail or the second rest api call could result in an error.
Our app is a message processing system with multiple components connected with RabbitMQ queues. So the message processing are asynchronous. Now I need to add a HTTP adapter that communicates with the system. Since HTTP is synchronous with request/response, I need a way to connect synchronous and asynchronous flows. The current solution is:
HTTP requests are sent to one queue. Each request has a unique request ID for correlation.
HTTP request is blocked by a CompletableFuture.
The request is processed and response is sent back to another queue.
Queue consumer uses response to complete the CompletableFuture matching with request ID.
The HTTP adapter is implemented using Akka HTTP. Requests are handled using handleWithAsyncHandler() with a function of type Function<HttpRequest, CompletionStage<HttpResponse>>.
The problem is that the HTTP adapter needs to manage a map (Map<String, CompletableFuture>) of all pending requests. For each request, a new CompletableFuture object is created and put into the map. When a response is received in the queue, the matching CompletableFuture is completed to finish the request. This seems a bad smell in the code because I need to carefully manage this map. For example, if a response failed to generate for a request, the request needs to be removed from the map.
I wonder if there are other ways than using a map to track all pending requests.
Basically, akka-http could be async style. You do not need to implement that queue to map the request Id.
One thing needs to be considered that DO NOT use the default dispatcher.
Better to define a blocking dispatcher to handle CompletableFuture.supplyAsync
For example
my-blocking-dispatcher {
type = Dispatcher
executor = "thread-pool-executor"
thread-pool-executor {
fixed-pool-size = 16
}
throughput = 1
}
import static akka.http.javadsl.server.Directives.completeWithFuture;
import static akka.http.javadsl.server.Directives.post;
// GOOD (the blocking is now isolated onto a dedicated dispatcher):
final Route routes = post(() -> {
final MessageDispatcher dispatcher = system.dispatchers().lookup("my-blocking-dispatcher");
return completeWithFuture(CompletableFuture.supplyAsync(() -> {
try {
Thread.sleep(5000L);
} catch (InterruptedException e) {
}
return HttpResponse.create()
.withEntity(Long.toString(System.currentTimeMillis()));
}, dispatcher // uses the good "blocking dispatcher" that we
// configured, instead of the default dispatcher to isolate the blocking.
));
});
I am using Spring Boot 1.4 and Java8. I want to know is it possible that if I receive a get request for an API in controller. I immediately return a response to the client and then create a background task for the request (that handle success and exception scenarios). I understand we can use completablefuture for async processing, but still from controller method for this API we generally send the response after using thenapply, exceptionally or get. That means though we have spawned a new thread. Main thread is still not free. I am looking for hit and forget kind of use case. Please suggest how it may be feasible.
as stated in comments you can use async functionality from Spring. For that you'll need a configuration like
#EnableAsync
#Configuration
public class AsyncConfig {
#Bean
public Executor threadPoolTaskExecutor() {
return new ConcurrentTaskExecutor(Executors.newCachedThreadPool());
}
}
then put the annotation on the method which is running the background task
#Async
void runBgTask() { /* ... */ }
and call it in your controller method
#GetMapping("/foo")
public Foo hello() {
runBgTask();
return new Foo();
}
I am analyzing some jersey 2.0 code and i have a question on how the following method works:
#Stateless
#Path("/mycoolstuff")
public class MyEjbResource {
…
#GET
#Asynchronous //does this mean the method executes on child thread ?
public void longRunningOperation(#Suspended AsyncResponse ar) {
final String result = executeLongRunningOperation();
ar.resume(result);
}
private String executeLongRunningOperation() { … }
}
Lets say im at a web browser and i type in www.mysite/mycoolstuff
this will execute the method but im not understanding what the asyncResponse is used for neither the #Asynchronous annotation. From the browser how would i notice its asychnronous ? what would be the difference in removing the annotation ? Also the suspended annotation after reading the documentation i'm not clear its purpose.
is the #Asynchronous annotation simply telling the program to execute this method on a new thread ? is it a convenience method for doing "new Thread(.....)" ?
Update: this annotation relieves the server of hanging onto the request processing thread. Throughput can be better. Anyway from the official docs:
Request processing on the server works by default in a synchronous processing mode, which means that a client connection of a request is processed in a single I/O container thread. Once the thread processing the request returns to the I/O container, the container can safely assume that the request processing is finished and that the client connection can be safely released including all the resources associated with the connection. This model is typically sufficient for processing of requests for which the processing resource method execution takes a relatively short time. However, in cases where a resource method execution is known to take a long time to compute the result, server-side asynchronous processing model should be used. In this model, the association between a request processing thread and client connection is broken. I/O container that handles incoming request may no longer assume that a client connection can be safely closed when a request processing thread returns. Instead a facility for explicitly suspending, resuming and closing client connections needs to be exposed. Note that the use of server-side asynchronous processing model will not improve the request processing time perceived by the client. It will however increase the throughput of the server, by releasing the initial request processing thread back to the I/O container while the request may still be waiting in a queue for processing or the processing may still be running on another dedicated thread. The released I/O container thread can be used to accept and process new incoming request connections.
#Suspended have more definite if you used it, else it will not make any difference of using it.
Let's talk about benefits of it:
#Suspended will pause/Suspend the current thread until it gets response,by default #NO_TIMEOUT no suspend timeout set. So it doesn't mean your request response (I/O)thread will get free and be available for other request.
Now Assume you want your service to be a response with some specific time, but the method you are calling from resource not guarantee the response time, then how will you manage your service response time? At that time, you can set suspend timeout for your service using #Suspended, and even provide a fall back response when time get exceed.
Below is some sample of code for setting suspend/pause timeout
public void longRunningOperation(#Suspended AsyncResponse ar) {
ar.setTimeoutHandler(customHandler);
ar.setTimeout(10, TimeUnit.SECONDS);
final String result = executeLongRunningOperation();
ar.resume(result);
}
for more details refer this
The #Suspended annotation is added before an AsyncResponse parameter on the resource method to tell the underlying web server not to expect this thread to return a response for the remote caller:
#POST
public void asyncPost(#Suspended final AsyncResponse ar, ... <args>) {
someAsyncMethodInYourServer(<args>, new AsyncMethodCallback() {
#Override
void completed(<results>) {
ar.complete(Response.ok(<results>).build());
}
#Override
void failed(Throwable t) {
ar.failed(t);
}
}
}
Rather, the AsyncResponse object is used by the thread that calls completed or failed on the callback object to return an 'ok' or throw an error to the client.
Consider using such asynchronous resources in conjunction with an async jersey client. If you're trying to implement a ReST service that exposes a fundamentally async api, these patterns allow you to project the async api through the ReST interface.
We don't create async interfaces because we have a process that takes a long time (minutes or hours) to run, but rather because we don't want our threads to ever sleep - we send the request and register a callback handler to be called later when the result is ready - from milliseconds to seconds later - in a synchronous interface, the calling thread would be sleeping during that time, rather than doing something useful. One of the fastest web servers ever written is single threaded and completely asynchronous. That thread never sleeps, and because there is only one thread, there's no context switching going on under the covers (at least within that process).
The #suspend annotation makes the caller actually wait until your done work. Lets say you have a lot of work to do on another thread. when you use jersey #suspend the caller just sits there and waits (so on a web browser they just see a spinner) until your AsyncResponse object returns data to it.
Imagine you had a really long operation you had to do and you want to do it on another thread (or multiple threads). Now we can have the user wait until we are done. Don't forget in jersey you'll need to add the " true" right in the jersey servlet definition in web.xml to get it to work.