CompletableFuture join vs CompletableFuture thenApply - spring

I have this two snippets in a Spring WebMVC controller:
First: thenApplyAsync
#RequestMapping(value = {"/index-standard"}, method = RequestMethod.GET)
public CompletableFuture<String> indexStandard(Model model) {
return projectService
.findMine(getCurrentApplicationUser())
.thenApplyAsync((result) -> {
model.addAttribute("projects", result);
return "/projectmanagement/my/index";
});
}
Second: join()
#RequestMapping(value = {"/index-nonstandard"}, method = RequestMethod.GET)
public String indexNonStandard(Model model) {
CompletableFuture<Iterable<ProjectDto>> mine = projectService.findMine(getCurrentApplicationUser());
CompletableFuture.allOf(mine).join();
model.addAttribute("projects", mine.join());
return "/projectmanagement/my/index";
}
For my understanding:
First option:
join() waits for execution of the CompletableFuture code.
the code is executed on a dedicated thread.
the http thread from the origin http request is available for further requests while the code executes
at the end (when the code is finished) the view will be rendered
Second option:
the same as the first option?
What is the difference in these options?
So is there a preferable solution (first or second)?
Both options work.

.join() will block the execution of the thread and wait until the result is ready. Usually, that's not the behaviour one wants when writing async applications.

Related

How to execute two Mono parrallel tasks in controller. Spring WebFlux

When calling the controller, I need to start two providers. One of them (personProvider) has to do its job in the background and write data to the Redis cache (I do not need the result of his work here). I need to map and send the result of the second (accountsProvider) to the calling service. Please, tell me how I can run them in parallel. My solution doesn't work, because they execute consistently.
#GetMapping(value = "/accounts", produces = MediaType.APPLICATION_JSON_VALUE)
public Mono<myDTO> accountsController(#RequestHeader("Channel") String channel,
#RequestHeader("Session") String sessionId) {
return clientSessionProvider.getClientSession(sessionId, channel) // return Mono<String>
.flatMap(clientData-> {
personProvider.getPersonCard(clientData) // My background task return Mono<PersonCard>
.subscribeOn(Schedulers.boundedElastic());
return accountsProvider.getAccounts(clientData) // return Mono<Accounts>
.subscribeOn(Schedulers.boundedElastic());
})
.map(myDTOMapper::map);
}
I create static Scheduler as field of my Controller class:
private static final Scheduler backgroundTaskScheduler = Schedulers.newParallel("backgroundTaskScheduler", 2);
public Mono<myDTO> accountsController(#RequestHeader("Channel") String channel,
#RequestHeader("Session") String sessionId) {
return clientSessionProvider.getClientSession(sessionId, channel)
.flatMap(clientData-> {
backgroundTaskScheduler.schedule(() -> personProvider.getPersonCard(clientData));
return accountsProvider.getAccounts(clientData);
})
.map(myDTOMapper::map);
In this case, my personProvider start in other thread and does't block the response from the controller.

Mutiny Uni Convert to Primitive Type

Up until now I have done very basic things with smallrye Mutiny in Quarkus. Basically, I have one or two very small web services which only interact with a web application. These services return a Uni<Response>.
Now I'm writing a logging service I want my others to pass information to. In this logging service, I need to return a value to calling services. The logging service will return this value as a Uni<Integer>. What I'm struggling with is how to extract the return value in the calling service as an int.
Here is the function in the logging service
#GET
#Path("/requestid")
#Produces(MediaType.TEXT_PLAIN)
public Uni<Integer> getMaxRequestId(){
return service.getMaxRequestId();
}
public Uni<Integer> getMaxRequestId() {
Integer result = Integer.valueOf(em.createQuery("select MAX(request_id) from service_requests").getFirstResult());
if(result == null) {
result = 0;
}
return Uni.createFrom().item(result += 1);
}
And here is the client side code in the calling service
#Path("/requests")
public class RequestIdResource {
#RestClient
RequestIdServices service;
#GET
#Path("/requestid")
#Produces(MediaType.TEXT_PLAIN)
public Uni<Integer> getMaxRequestId(){
return service.getMaxRequestId();
}
}
public void filter(ContainerRequestContext requestContext) throws IOException {
int requestid = client.getMaxRequestId();
rm.name = ConfigProvider.getConfig().getValue("quarkus.application.name", String.class);
rm.server = requestContext.getUriInfo().getBaseUri().getHost();
rm.text = requestContext.getUriInfo().getPath(true);
rm.requestid = requestid;
}
Basically everything I have tried creates another Uni. Maybe I am simply using the concept all wrong. But how do I get the Integer out of the Uni so I can get the intValue?
You need to invoke a terminal operation, or use the value and continue the chain.
If you want to invoke a terminal operator you can invoke the await operation to make your code blocking and wait for the response.
If you want to merge this reactive invocation with another that is present in your client code, you can join or combine your actual Mutiny stream with the on coming from the response by using the combine method.
If you just want to use the value and do not retrieve it, you can suscribe and get the result.
If you have a multi you can call directly the method toList
Assuming that you want to have some timeouts involved and you want to get the actual Integer, you can go with the await method and a timeout.

Spring boot async call with CompletableFuture, exception handling

I have a Spring boot service with some code like below for parallel async call:
CompletableFuture future1 = accountManager.getResult(url1);
CompletableFuture future2 = accountManager.getResult(url2);
CompletableFuture.allOf(future1, future2).join();
String result1 = future1.get();
String result2 = future2.get();
It works fine when there is no exception. My question is how to handle exception? If getting future1 failed (let say url2 is an invalid url), I still want future2 back as partial result of allOf method. How should I do it?
Thanks!
CompletableFuture comes with a block called exceptionally() which can be used handle the exceptions happen inside the asynchronous code block. Snippet of getResult method for your reference,
public CompletableFuture<String> getGreeting(String url) {
return CompletableFuture.supplyAsync( () -> {
return // Business logic..
}, executor).exceptionally( ex -> {
log.error("Something went wrong : ", ex);
return null;
});
}
In this case the block would return null in case of exception and allOf method would lead to a completion where you can filter the one resulted in the exception when you fetch individual futures.

Tracking response times of API calls in springboot

I'm looking to track the response times of API calls.
I then want to plot the response times of the calls( GET, PUT, POST DELETE) on a graph afterwards to compare the time differences.
This is what I'm currently doing to find the response time of a GET call but I'm not quite sure if it's right.
#RequestMapping(value="/Students", method = RequestMethod.GET)
public ResponseEntity<List<Students>> getStudents()
{
long beginTime = System.currentTimeMillis();
List<Students> students = (List<Students>) repository.findAll();
if(students.isEmpty())
{
return new ResponseEntity(HttpStatus.NO_CONTENT);
}
long responseTime = System.currentTimeMillis() - beginTime;
logger.info("Response time for the call was "+responseTime);
return new ResponseEntity(students, HttpStatus.OK);
}
I believe I am returning the response time before I actually return the data to the client which is the whole point of this but I wouldn't be able to put it after the return statement as it would be unreachable code.
Are there any better ways of trying to track the times of the calls?
You can use Around Advice of springboot and in the advice you can log the time. The way it works is once a call is made to the controller, the Around Advice intercepts it and starts a Timer(to record the time taken). From the advice we proceed to the main controller using jointPoint.proceed() method. Once the controller returns the value you can log the timer value. return the Object.
Here is the sample code:
in build.grale include
compile("org.aspectj:aspectjweaver:1.8.8")
Create a Component Class and put around #Aspect
#Component
#Aspect
public class advice{
#Around(("#annotation(logger)")
public Object loggerAspect(ProceedingJoinPoint joinPoint){
// start the Timer
Object object = jointPoint.proceed();
// log the timer value
return object;
}
}
Add annotation #logger in the controller method. you are good to go.
Hope this helps.
you can refer the link for full explanation.

Long computation AJAX causing duplicate controller Play Framework controller action calls

Basic Problem:
If I make an AJAX call to a controller method that performs a long computation (60 seconds or greater), I get a duplicate thread that comes in and follows the same path of execution (as best as I can tell from stack trace dumps -- and only one, this doesn't continue happening with the second thread). This appears to only happen when the controller action is called via AJAX. This can easily be replicated by creating a dummy controller method with nothing in it by a Thread.sleep() call that returns when finished.
I've tested this in a method that's loaded without an AJAX call and it doesn't produce the rogue thread. I tried various forms of AJAX calls (several forms of jQuery methods and base JavaScript) and got the same result with each. I initially thought it might be a thread problem so I implemented the dummy method using Promise(s) (http://www.playframework.com/documentation/2.1.x/JavaAsync, and http://www.playframework.com/documentation/2.1.x/JavaAkka) and AsyncResult, but it had no effect.
I know that the two threads are using the same execution context. Is that causing the problem here? Is it avoidable by moving the long computation to another context? Any ideas as to where this second, duplicate thread is coming from?
Controller Method (Long Computation):
public static Result test()
{
Logger.debug("*** TEST Controller entry: threadId=" + Thread.currentThread().getId());
StackTraceElement[] stack = Thread.currentThread().getStackTrace();
for(StackTraceElement e : stack)
{
Logger.debug("***" + e.toString());
}
Promise<Void> promiseString = Akka.future(
new Callable<Void>() {
public Void call() {
try
{
Logger.debug("*** going to sleep: threadId=" + Thread.currentThread().getId());
Thread.sleep(90000);
}
catch(InterruptedException e)
{
//swallow it whole and move on
}
return null;
}
}
);
Promise<Result> promiseResult = promiseString.map(
new Function<Void, Result>() {
public Result apply(Void voidParam) {
return ok("done");
}
}
);
return async(promiseResult);
}

Resources