Skip to content

Instantly share code, notes, and snippets.

@MichalAdorno
Last active January 17, 2024 18:59
Show Gist options
  • Save MichalAdorno/be3d3f0af649696d6ef8fee0c5ed80a6 to your computer and use it in GitHub Desktop.
Save MichalAdorno/be3d3f0af649696d6ef8fee0c5ed80a6 to your computer and use it in GitHub Desktop.
Combining CompletableFuture API with Spring's DeferredResult
//--------------------------------------------------------
//Service that we want to execute asynchroneously - consists of the following method:
public String execute() {
try {
Thread.sleep(5000);
logger.info("Slow task executed");
return "Task finished";
} catch (InterruptedException e) {
throw new RuntimeException();
}
}
//--------------------------------------------------------
//Controller
@RequestMapping(value = "/deferred", method = RequestMethod.GET, produces = "text/html")
public DeferredResult<String> executeSlowTask() {
logger.info("Request received");
//1a . declare a DeferredResult variable
DeferredResult<String> deferredResult = new DeferredResult<>();
//(1b) declare callbacks (onCompletion, onTimeout, onError eg.:
deferredResult.onError((Throwable t) -> {
deferredResult.setErrorResult("An error occurred.")); //note the mutator method of DeferredResult - there is one for each case (normal / exceptional / etc)
});
//2 submit to an <EXECUTOR-SERVICE> the method you want to execute asynchroneously (through a CompletableFuture)
CompletableFuture.supplyAsync(taskService::execute, <EXECUTOR-SERVICE>)
//3 chain CompletableFuture API operations in order to assign the result of the method into the declared DeferredResult object
.whenCompleteAsync((result, throwable) -> deferredResult.setResult(result));
/*
public CompletableFuture<T> whenCompleteAsync(BiConsumer<? super T,? super Throwable> action)
Returns a new CompletionStage with the same result or exception as this stage,
that executes the given action using this stage's default
asynchronous execution facility when this stage completes.
When this stage is complete, the given action is invoked with the result
(or null if none) and the exception (or null if none) of this stage as arguments.
The returned stage is completed when the action returns.
If the supplied action itself encounters an exception,
then the returned stage exceptionally completes with
this exception unless this stage also completed exceptionally.
*/
//4
logger.info("Servlet thread released");
return deferredResult;
}
/*
Compare with:
* https://nickebbitt.github.io/blog/2017/03/22/async-web-service-using-completable-future
* https://xpadro.com/2015/07/understanding-callable-and-spring-deferredresult.html
*/
//----------------------------------------------------
//Another example of Controller - we can return a CompletableFuture tied to a DeferredResult from the Controller directly:
@RequestMapping(path = "/asyncCompletable", method = RequestMethod.GET)
public CompletableFuture<String> getValueAsyncUsingCompletableFuture() {
log.info("Request received");
CompletableFuture<String> completableFuture =
CompletableFuture.supplyAsync(this::processRequest); //this CompletableFuture is then directly passed to the Servlet
log.info("Servlet thread released");
return completableFuture;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment