How can I implement asynchronous processing in a Java Spring 3-tier application to handle long-running tasks that are expected to take more than 30 seconds, while providing an immediate response to the client after 30 seconds with the message 'Processing in progress. We will notify you when it's completed' Then continue the work and processing in the background. Once the background work is completed, I only need to log the completion without sending any further response to the client.
Note: I work in both JAVA 17 and JAVA 8, so I found most of the functionality didn't work as expected in both of them.
in my controller, I used this :
CompletableFuture.delayedExecutor(30, TimeUnit.SECONDS)
and also like this
Timer timer = new Timer();
timer.schedule(new TimerTask() {
@Override
public void run() {
// return ResponseEntity with the message 'Processing in progress...'
}
}, 30000);
You are making things overly complex. You should be calling an @Async
service method, which would return a CompletableFuture
(or you can inject the AsyncTaskExecutor
and use the submitCompletable
to wrap the service call (instead of annotating it with @Async
and return a CompletableFuture
).
In the controller use a DeferredResult
which will send the result as soon as it is available from the CompletableFuture
through the CompletableFuture
callback methods. It will also have an onTimeout
callback (for 30 seconds) which will fire if the process didn't finish within 30 seconds. It will keep the background process running but will return an answer to the client.
// Deferred Result with 30 second timeout
DeferredResult<ResponseEntity<?>> result = new DeferredResult(30_000, () -> ResponseEntity.accepted().body("Processing").build());
CompletableFuture<YourResult> future = ... // However you achieve this
future.whenComplete( (res, ex) -> {
if (res != null) {
res.setResult(ResponseEntity.ok(res));
} else {
res.setErrorResult(ex);
}
});
return result;
Something along those lines. The DeferredResult
will wait for 30 seconds, if not return a default response (HTTP 200 ACCEPTED with a message, when the CompletableFuture
completes it will return a regular response, or if it was an exception return that).