-
Notifications
You must be signed in to change notification settings - Fork 136
Example : Building a non blocking NIO 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.
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.
AsyncRestTemplate template = new AsyncRestTemplate(
new HttpComponentsAsyncClientHttpRequestFactory());
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);
oops - my bad