Forked from MichalAdorno/DeferredResultAndCompletableFuture.java
Created
July 17, 2020 06:21
-
-
Save kamzrk/4e02242c6a8496d44cc18e7a3f2bdd1d to your computer and use it in GitHub Desktop.
Combining CompletableFuture API with Spring's DeferredResult
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//-------------------------------------------------------- | |
//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