Skip to content

Example : Building a non blocking NIO rest client

johnmcclean-aol edited this page Feb 3, 2015 · 1 revision

SimpleReact with an NIO Asynchronous Rest Client

Imagine your application recieves a large volume of external requests per second. Each of those requests, in turn, spawn an additional large number of REST calls to internal microservices. E.g. we recieve ~100 simulatanous requests each of which spawns another 20 requests. To handle this load alone, we may need up to 2,100 threads available on our server.

In such an environment, particularly one that was resource constrained, we could easily run out of threads when making the REST calls to our internal microservers. The I/O bound REST calls would then block the other CPU bound tasks that need to be executed, grinding processing on our server to a halt.

With an NIO REST client we can prevent the I/O bound REST calls from hogging all of the available threads.

With a SimpleReact reactive flow we can respond to the results of REST calls asynchronously, and concurrently, when they arrive.

This is very easy to setup

The Spring framework provides an abstraction over Apaches' NIO based HttpAsyncClient that returns a Spring ListenableFuture. While SimpleReact does not support Spring's ListenableFuture abstraction, it is trivial to wrap that in a CompletableFuture which SimpleReact does support. See : http://blog.krecan.net/2014/06/11/converting-listenablefutures-to-completablefutures-and-back/. for an example of how to implement a toCompletableFuture method.

Spring code

AsyncRestTemplate template = new AsyncRestTemplate(
            new HttpComponentsAsyncClientHttpRequestFactory());

SimpleReact code

Given a List of URLS e.g.

List<String> urls = Arrays.asList("http://advertising.com",
        "http://aol.com",
        "http://www.marketplacebyadtech.com/",
        "http://www.adlearnop.com");

We can convert that List into a Stream of CompletableFutures which SimpleReact can use to kick off a Reactive Dataflow.

return new SimpleReact()
    .fromStream(urls.stream()
            .map(it ->  
                toCompletableFuture(template
                            .getForEntity(it,String.class))))
    .then(it -> it.getBody())
    .then(it -> extractTitle(it))
    .block(status -> status.getAllCompleted() >3 && status.getElapsedMillis()>300);
Clone this wiki locally