javaspringspring-web

spring async rest client orchestrate few calls


I have following problem in my service I am building object X however In order to build it I need to make few http calls in order to get all required data to fill it (each rest fills certain part of the object.) In order to keep performance high I thought it would be nice to make call async and after all calls are done return object to the caller. It looks something like this

ListenableFuture<ResponseEntity<String>> future1 = asycTemp.exchange(url, method, requestEntity, responseType);
future1.addCallback({
    //process response and set fields
    complexObject.field1 = "PARSERD RESPONSE"
},{
    //in case of fail fill default or take some ather actions
})

I don't know how to wait for all features to be done. I guess that they are some standard spring ways of solving this kind of issue. Thanks in advance for any suggestions. Spring version - 4.2.4.RELEASE Best regards


Solution

  • Adapted from Waiting for callback for multiple futures.

    This example simply requests the Google and Microsoft homepages. When the response is received in the callback, and I've done my processing, I decrement a CountDownLatch. I await the CountDownLatch, "blocking" the current thread until the CountDownLatch reaches 0.

    It's important that you decrement if your call fails or succeeds, as you must hit 0 to continue with the method!

    public static void main(String[] args) throws Exception {
        String googleUrl = "http://www.google.com";
        String microsoftUrl = "http://www.microsoft.com";
        AsyncRestTemplate asyncRestTemplate = new AsyncRestTemplate();
        ListenableFuture<ResponseEntity<String>> googleFuture = asyncRestTemplate.exchange(googleUrl, HttpMethod.GET, null, String.class);
        ListenableFuture<ResponseEntity<String>> microsoftFuture = asyncRestTemplate.exchange(microsoftUrl, HttpMethod.GET, null, String.class);
        final CountDownLatch countDownLatch = new CountDownLatch(2);
        ListenableFutureCallback<ResponseEntity<java.lang.String>> listenableFutureCallback = new ListenableFutureCallback<ResponseEntity<String>>() {
    
            public void onSuccess(ResponseEntity<String> stringResponseEntity) {
                System.out.println(String.format("[Thread %d] Status Code: %d. Body size: %d",
                        Thread.currentThread().getId(),
                        stringResponseEntity.getStatusCode().value(),
                        stringResponseEntity.getBody().length()
                ));
                countDownLatch.countDown();
            }
    
            public void onFailure(Throwable throwable) {
                System.err.println(throwable.getMessage());
                countDownLatch.countDown();
            }
        };
        googleFuture.addCallback(listenableFutureCallback);
        microsoftFuture.addCallback(listenableFutureCallback);
        System.out.println(String.format("[Thread %d] This line executed immediately.", Thread.currentThread().getId()));
        countDownLatch.await();
        System.out.println(String.format("[Thread %d] All responses received.", Thread.currentThread().getId()));
    
    }
    

    The output from my console:

    [Thread 1] This line executed immediately.
    [Thread 14] Status Code: 200. Body size: 112654
    [Thread 13] Status Code: 200. Body size: 19087
    [Thread 1] All responses received.