JingJong
JingJong

Reputation: 247

Spring boot Async with Multithreading

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

Answers (2)

Ajit Soman
Ajit Soman

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

Maxim Popov
Maxim Popov

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

Related Questions