Reputation: 247
I have a spring boot microservice where we call multiple services(Lets say Service A and Service B). I am trying to call these two services Asynchronously on multiple threads based on some conditions and once processing is completed I would like to merge the response from Service A and ServiceB.
I know we can use @Async to run a process asynchronously and use ExecutorService to start multiple threads for a service.
But i am not Sure How to keep all things together. So looking for any suggestions here?
@Async
Service A(thread1,thread2) \
MicroService / (Merge from Response of ServiceA and ServiceB)
\ @Async
Service B(thread1,thread2) /
I know this is mostly theoretically explained above, but i tried following / going through multiple websites but Most of the articles either explains about Aync or Multithreading but not sure how to wait and run two process in Async in multiple threads and continue execution after these two service calls are completed!
Any Suggestions or leads are appreciated! TIA :)
Upvotes: 16
Views: 40639
Reputation: 4074
You need to use spring's AsyncResult
class to wrap your result and then use its method .completable()
to return CompletableFuture
object.
When merging future object use CompletableFuture.thenCompose() and CompletableFuture.thenApply() method to merge the data like this:
CompletableFuture<Integer> result = futureData1.thenCompose(fd1Value ->
futureData2.thenApply(fd2Value ->
merge(fd1Value, fd2Value)));
Here is a basic example:
Annotate Spring boot main class with @EnableAsync
annotation
@SpringBootApplication
@EnableAsync
public class StackOverflowApplication {
public static void main(String[] args) {
SpringApplication.run(StackOverflowApplication.class, args);
}
}
Create a sample service which will return CompletableFuture
Aservice.java
@Service
public class Aservice {
@Async
public CompletableFuture<Integer> getData() throws InterruptedException {
Thread.sleep(3000); // sleep for 3 sec
return new AsyncResult<Integer>(2).completable(); // wrap integer 2
}
}
Bservice.java
@Service
public class Bservice {
@Async
public CompletableFuture<Integer> getData() throws InterruptedException {
Thread.sleep(2000); // sleep for 2 sec
return new AsyncResult<Integer>(1).completable(); // wrap integer 1
}
}
Create another service which will merge other two service data
ResultService.java
@Service
public class ResultService {
@Autowired
private Aservice aservice;
@Autowired
private Bservice bservice;
public CompletableFuture<Integer> mergeResult() throws InterruptedException, ExecutionException {
CompletableFuture<Integer> futureData1 = aservice.getData();
CompletableFuture<Integer> futureData2 = bservice.getData();
// Merge futures from Aservice and Bservice
return futureData1.thenCompose(
fd1Value -> futureData2.thenApply(fd2Value -> fd1Value + fd2Value));
}
}
Create a sample controller for testing
ResultController.java
@RestController
public class ResultController {
@Autowired
private ResultService resultService;
@GetMapping("/result")
CompletableFuture<Integer> getResult() throws InterruptedException, ExecutionException {
return resultService.mergeResult();
}
}
Upvotes: 22
Reputation: 1227
You can look to a java's CompletableFuture. The ComplitableFuture allows to union several async tasks (which also are CompletableFuture) and waits for a result of all CompletableFutures.I am not sure that it is exactly fit for your case, but it may be helpful. https://www.baeldung.com/java-completablefuture#Multiple
Upvotes: 2