Call multiple synchronous tasks asynchronously using RxJava - java

I have an async task represented by Futures executing in a separate threadpool that I want to join using RxJava. The "old" way of doing it using Java 5 constructs would be something like this (omitting collecting the results):
final Future<Response> future1 = wsClient.callAsync();
final Future<Response> future2 = wsClient.callAsync();
final Future<Response> future3 = wsClient.callAsync();
final Future<Response> future4 = wsClient.callAsync();
future1.get();
future2.get();
future3.get();
future4.get();
This would block my current thread until all futures are completed, but the calls would be in parallell and the whole operation would only take the time equal to the longest call.
I want to do the same using RxJava, but I'm a bit noob when it comes to how to model it correctly.
I've tried the following, and it seems to work:
Observable.from(Arrays.asList(1,2,3,4))
.flatMap(n -> Observable.from(wsClient.callAsync(), Schedulers.io()))
.toList()
.toBlocking()
.single();
The problem with this approach is that I introduce the Schedulers.io threadpool which causes unnecessary thread switching as I'm already blocking the current thread (using toBlocking()).
Is there any way I can model the Rx flow to execute the tasks in parallel, and block until all has been completed?

You should use zip function.
For example like this:
Observable.zip(
Observable.from(wsClient.callAsync(), Schedulers.io()),
Observable.from(wsClient.callAsync(), Schedulers.io()),
Observable.from(wsClient.callAsync(), Schedulers.io()),
Observable.from(wsClient.callAsync(), Schedulers.io()),
(response1, response2, response3, response4) -> {
// This is a zipping function...
// You'll end up here when you've got all responses
// Do what you want with them and return a combined result
// ...
return null; //combined result instead of null
})
.subscribe(combinedResult -> {
// Use the combined result
});
Observable.zip can also work with an Iterable so you can wrap your Observable.from(wsClient.callAsync(), Schedulers.io()); around with one (that returns 4 of those).

Related

io.smallrye.mutiny.Uni multi threading doesn't work (Quarkus)

I try to perform 2 different operations with different threads each.Here is my code :
Uni.combine().all()
.unis(getItem(), getItemDetails())
.asTuple().subscribe().with(tuple -> {
context.setItem(tuple.getItem1());
context.setItemDetails(tuple.getItem2());
});
Methods :
public Uni<ItemResponse> callGetItem(){
Supplier<ItemResponse> supplier = () -> itemService.getItem("item_id_1");
return Uni.createFrom().item(supplier);
}
public Uni<ItemDetailsResponse> callGetItemDetail(){
Supplier<ItemDetailsResponse> supplier = () -> itemService.getItemDetail("dummy_item_id");
return Uni.createFrom().item(supplier) ;
}
But when i run the code both callGetItem() and callGetItemDetail() methods works in the same thread (executor-thread-0).
Where am i doing wrong?
Edit:
When i give an executor service Executors.newFixedThreadPool(2) for my Unis,
They still work in single thread. I mofified callGetItem() and callGetItemDetail() as :
public Uni<ItemResponse> callGetItem(){
Supplier<ItemResponse> supplier = () -> itemService.getItem("item_id_1");
return Uni.createFrom().item(supplier).emitOn(executor);
}
public Uni<ItemDetailsResponse> callGetItemDetail(){
Supplier<ItemDetailsResponse> supplier = () -> itemService.getItemDetail("dummy_item_id");
return Uni.createFrom().item(supplier).emitOn(executor) ;
}
executor is :
ExecutorService executor = Executors.newFixedThreadPool(2);
but they still works in same thread. Do you have any idea why it happens?
Since you are composing different Unis using Uni.combine().all().unis().asTuple(), the combined Uni will emit its result (combination) after the last element has emitted its item.
The last (upstream) Uni will have its item emitted (as is the case for other Unis as well) on whatever Thread that you have declaratively set it to emit on. Hence the combination Uni will follow execution on the same calling Thread.
As a result, if you are accessing the combined group values, you will be accessing these on the same execution carrier Thread.

Async Verticle vs Composite Future Verticle. How are they different?

I have two Hello World handle methods written in Kotlin Vert.x. I want to get a clear understanding of how they are working, if possible in detail. One is AsyncVertilce while other is CompositeVerticle.
This one is Hello World Coroutine Async Verticle handle method.
var result = async {
callFunctionAwait(
getDependentAddress(HELLO_WORLD), message.headers(), message.body(), messageMarker
)
}
var result1 = async {
callFunctionAwait(
getDependentAddress(HELLO_WORLD), message.headers(), message.body(), messageMarker
)
}
// both requests are going to execute in parallel
val res = result.await()
val res1 = result1.await()
message.reply(res.body, DeliveryOptions().setHeaders(res1.headers))
}
This one is Hello World Coroutine Composite Verticle
var future1 = callFunction(getDependentAddress(HELLO_WORLD), message.headers(), message.body(), messageMarker)
var future2 = callFunction(getDependentAddress(HELLO_WORLD), message.headers(), message.body(), messageMarker)
val result = CompositeFuture.all(future1, future2).await()
if (result.succeeded()) {
message.reply(future1.result().body, DeliveryOptions().setHeaders(future2.result().headers))
} else {
log.error(messageMarker, "Request failed with an exception ", result.cause())
message.fail(500, result.cause().message)
}
}
From the documentation
CompositeFuture.all() takes several futures arguments (up to 6) and
returns a future that is succeeded when all the futures are succeeded
and failed when at least one of the futures is failed
One of the main use cases is when you want all or nothing operations; when you expect a single result for a given number of futures.
There are other variants of CompositeFuture like CompositeFuture.any and CompositeFuture.join
The async way of executing futures, will run each future individually and their results will be gotten irrespective of the other future(s).

How to make threads in ExecutorService to wait stage

In my web application, I need to call around more than 10 methods in one API call. To make that efficient I use ExecutorService to create multiple threads at a same time. Each methods returning different Objects expect fav_a(), fav_b(), fav_c(). (Sample code is given below for easiness)
#GetMapping(RequestUrl.INIT)
public ResponseEntity<Map<String, List<?>>> init() throws ExecutionException, InterruptedException {
ExecutorService service = Executors.newFixedThreadPool(6);
Future<List<Object>> method_a = service.submit(() -> someService.method_a());
Future<List<Object>> method_b = service.submit(() -> someService.method_b());
Future<List<Object>> method_c = service.submit(() -> someService.method_c());
Future<List<FavouriteConverter>> fav_a = service.submit(() -> someService.fav_a());
Future<List<FavouriteConverter>> fav_b = service.submit(() -> someService.fav_b());
Future<List<FavouriteConverter>> fav_c = service.submit(() -> someService.fav_c());
service.shutdown();
List<FavouriteConverter> combinedFavourite = Stream.of(fav_a.get(), fav_b.get(), fav_c.get()).flatMap(f -> f.stream()).collect(Collectors.toList());
combinedFavourite=combinedFavourite.stream()
.sorted(Comparator.comparing(FavouriteConverter::get_id, Comparator.reverseOrder()))
.limit(25)
.collect(Collectors.toList());
Map<String, List<?>> map = new HashMap<>();
map.put("method_a", method_a.get());
map.put("method_b", method_b.get());
map.put("method_c", method_c.get());
map.put("favourite", combinedFavourite);
return new ResponseEntity<>(map, HttpStatus.OK);
}
First I need to get fav_a.get(), fav_b.get(), fav_c.get() to make combinedFavourite. If any of one delays, the logic will be wrong. Creating threads are expensive.
Does Stream automatically handle this kind of situation?
If fav_a(), fav_b(), fav_c() do it jobs earlier than other methods, How can I put combinedFavourite into another thread? This means how to make Future<List<FavouriteConverter>> combinedFavourite in waiting stage until fav_a.get(), fav_b.get(), fav_c.get() finishes. (Assume method_a(),method_b(),method_c() still running.)
No, Streams are not responsible for joining these threads.
Since you wait for the results of these 3 threads and putting them into a map which you return, wrapping such logic in a separate thread doesn't help you as long as you have to wait and return the result.
Use ExecutorService::invokeAll to execute all the tasks and returning a list of Futures when all are complete (when Future::done is true).
List<Future<List<Object>>> list = service.invokeAll(
Arrays.asList(
() -> someService.method_a(),
() -> someService.method_b(),
() -> someService.method_c()
));
Note these are guaranteed:
The result List<Future> is in the same order as the collection of tasks given (according to its Iterator).
All the tasks will run in a separate thread if the pooled number of threads are higher or equal than executed tasks (assuming there are no other tasks using a thread from the same thread pool).
This logics helps you to work with complete results.

Why main thread is not waiting for other async process(threads) to complete. allOff not working properly

I am calling one async method inside for loop and adding future of it into a list. I am not sure why allOff is not waiting to complete all futures and returning partial result. Have a look of my code.
I have one overridden method
#Overide
#Async
CompletableFuture<someType> fetchData()
{
returns new CompletableFuture<someType>();
}
I am calling above method in a for loop with different instances.
get all beans which implments one interface which has mehod fetchData.
Map<String, SomeClass> allBeans =context.getBeansOfType(SomeClass.class);
List<SomeClass> list=
allBeans.values().stream().collect(SomeClass.toList());
for (SomeClass classInstance: list) {
classInstance.fetchData().thenApply(x->{
//Some DB persistence Call
futureList.add(x);
});
}
after that I am applying allOff so that all future can be completed but it is not waiting for all and main thread excuting rest of flow.
CompletableFuture<Void> combinedFutures = CompletableFuture.allOf(
futureList.toArray(new CompletableFuture[futureList.size()]));
CompletableFuture<List<futureResponse>> finalList=
combinedFutures.thenApply(v -> {
return futureList.stream().map(m ->
m.join()).collect(Collectors.toList());
});
finalList- in this List I want all the completed futures returned by fetch
invocation.
In finalList I am always getting 2 objects but fetchData is getting run 5 times( based on number of instances), I saw the log after all of remaining async call are getting completed. Could someone help here.
Observation:- After putting main thread on sleep for 30 sec, I could see I have all 5 objects in the list. Could some one please tell why main thread is not waiting at allOff for all futures to complete.
IIUC, what you want to do can be done simpler by doing
CompletableFuture<List<FutureResponse>> = CompletableFuture.supplyAsync(() -> {
// start fetches and collect the individual futures
List<CompletableFuture> fetches =
allBeans.values().stream()
.map(SomeClass::fetchData)
.collect(toList());
// join all futures and return the list of the results
return fetches.stream()
.map(CompletableFuture::join)
.collect(toList());
}
I think you can't do it in a single stream (ie map to fetch, then immediately to join) because that might wait for the join before the next future is created.
You have a race condition :
classInstance.fetchData().thenApply(x->{
futureList.add(x);
});
This code means that only when the future x is completed, then x will be added to futureList. This might be in 10 milliseconds, or 2 hours, who knows ? (It might be never if the future fails exceptionnaly).
So, when the code reaches
CompletableFuture.allOf(futureList....
There is no "guarantee" that the thenApply have been called. futureList could even be empty.
One way you could correct this code is like so :
Map<String, SomeClass> allBeans =context.getBeansOfType(SomeClass.class);
List<SomeClass> list=
allBeans.values().stream().collect(SomeClass.toList());
for (SomeClass classInstance: list) {
futureList.add(classInstance.fetchData());
}
Or if you actually need to do something in a thenApply:
for (SomeClass classInstance: list) {
futureList.add(
classInstance.fetchData().thenApply(x -> whatever(x))
);
}
This way, your futureList is populated not when an async result returns (which is unknown, and might even fail with an exception an never occur), but as soon as the async call is created, which is what you actually want.

How to use AsyncRestTemplate to make multiple calls simultaneously?

I don't understand how to use AsyncRestTemplate effectively for making external service calls. For the code below:
class Foo {
public void doStuff() {
Future<ResponseEntity<String>> future1 = asyncRestTemplate.getForEntity(
url1, String.class);
String response1 = future1.get();
Future<ResponseEntity<String>> future2 = asyncRestTemplate.getForEntity(
url2, String.class);
String response2 = future2.get();
Future<ResponseEntity<String>> future3 = asyncRestTemplate.getForEntity(
url3, String.class);
String response3 = future3.get();
}
}
Ideally I want to execute all 3 calls simultaneously and process the results once they're all done. However each external service call is not fetched until get() is called but get() is blocked. So doesn't that defeat the purpose of AsyncRestTemplate? I might as well use RestTemplate.
So I don't understaand how I can get them to execute simultaneously?
Simply don't call blocking get() before dispatching all of your asynchronous calls:
class Foo {
public void doStuff() {
ListenableFuture<ResponseEntity<String>> future1 = asyncRestTemplate
.getForEntity(url1, String.class);
ListenableFuture<ResponseEntity<String>> future2 = asyncRestTemplate
.getForEntity(url2, String.class);
ListenableFuture<ResponseEntity<String>> future3 = asyncRestTemplate
.getForEntity(url3, String.class);
String response1 = future1.get();
String response2 = future2.get();
String response3 = future3.get();
}
}
You can do both dispatch and get in loops, but note that current results gathering is inefficient as it would get stuck on the next unfinished future.
You could add all the futures to a collection, and iterate through it testing each future for non blocking isDone(). When that call returns true, you can then call get().
This way your en masse results gathering will be optimised rather than waiting on the next slow future result in the order of calling get()s.
Better still you can register callbacks (runtimes) within each ListenableFuture returned by AccyncRestTemplate and you don't have to worry about cyclically inspecting the potential results.
If you don't have to use 'AsyncRestTemplate' I would suggest to use RxJava instead. RxJava zip operator is what you are looking for. Check code below:
private rx.Observable<String> externalCall(String url, int delayMilliseconds) {
return rx.Observable.create(
subscriber -> {
try {
Thread.sleep(delayMilliseconds); //simulate long operation
subscriber.onNext("response(" + url + ") ");
subscriber.onCompleted();
} catch (InterruptedException e) {
subscriber.onError(e);
}
}
);
}
public void callServices() {
rx.Observable<String> call1 = externalCall("url1", 1000).subscribeOn(Schedulers.newThread());
rx.Observable<String> call2 = externalCall("url2", 4000).subscribeOn(Schedulers.newThread());
rx.Observable<String> call3 = externalCall("url3", 5000).subscribeOn(Schedulers.newThread());
rx.Observable.zip(call1, call2, call3, (resp1, resp2, resp3) -> resp1 + resp2 + resp3)
.subscribeOn(Schedulers.newThread())
.subscribe(response -> System.out.println("done with: " + response));
}
All requests to external services will be executed in separate threads, when last call will be finished transformation function( in example simple string concatenation) will be applied and result (concatenated string) will be emmited from 'zip' observable.
What I Understand by Your question is You have a predefined asynchronous method and you try to do is call this method asynchoronously using RestTemplate Class.
I have wrote a method that will help you out to call Your method asynchoronously.
public void testMyAsynchronousMethod(String... args) throws Exception {
// Start the clock
long start = System.currentTimeMillis();
// Kick of multiple, asynchronous lookups
Future<String> future1 = asyncRestTemplate
.getForEntity(url1, String.class);;
Future<String> future2 = asyncRestTemplate
.getForEntity(url2, String.class);
Future<String> future3 = asyncRestTemplate
.getForEntity(url3, String.class);
// Wait until they are all done
while (!(future1 .isDone() && future2.isDone() && future3.isDone())) {
Thread.sleep(10); //10-millisecond pause between each check
}
// Print results, including elapsed time
System.out.println("Elapsed time: " + (System.currentTimeMillis() - start));
System.out.println(future1.get());
System.out.println(future2.get());
System.out.println(future3.get());
}
You might want to use CompletableFuture class (javadoc).
Transform your calls into CompletableFuture. For instance.
final CompletableFuture<ResponseEntity<String>> cf = CompletableFuture.supplyAsync(() -> {
try {
return future.get();
} catch (InterruptedException | ExecutionException e) {
throw new RuntimeException(e);
}
});
Next call CompletableFuture::allOf method with your 3 newly created completable futures.
Call join() method on the result. After the resulting completable future is resolved you can get the results from each separate completable future you've created on step 3.
I think you are misunderstanding a few things here. When you call the getForEntity method, the requests are already fired. When the get() method of the future object is called, you are just waiting for the request to complete. So in order fire all those three requests on the same subsecond, you just have to do:
// Each of the lines below will fire an http request when it's executed
Future<ResponseEntity<String>> future1 = asyncRestTemplate.getForEntity(url1, String.class);
Future<ResponseEntity<String>> future2 = asyncRestTemplate.getForEntity(url2, String.class);
Future<ResponseEntity<String>> future3 = asyncRestTemplate.getForEntity(url3, String.class);
After all these codes are run, all the requests are already fired (most probably in the same subsecond). Then you can do whatever you want in the meanwhile. As soon as you call any of the get() method, you are waiting for each request to complete. If they are already completed, then it will just return immediately.
// do whatever you want in the meantime
// get the response of the http call and wait if it's not completed
String response1 = future1.get();
String response2 = future2.get();
String response3 = future3.get();
I don't think any of the previous answers actually achieve parallelism. The problem with #diginoise response is that it doesn't actually achieve parallelism. As soon as we call get, we're blocked. Consider that the calls are really slow such that future1 takes 3 seconds to complete, future2 2 seconds and future3 3 seconds again. With 3 get calls one after another, we end up waiting 3 + 2 + 3 = 8 seconds.
#Vikrant Kashyap answer blocks as well on while (!(future1 .isDone() && future2.isDone() && future3.isDone())). Besides the while loop is a pretty ugly looking piece of code for 3 futures, what if you have more? #lkz answer uses a different technology than you asked for, and even then, I'm not sure if zip is going to do the job. From Observable Javadoc:
zip applies this function in strict sequence, so the first item
emitted by the new Observable will be the result of the function
applied to the first item emitted by each of the source Observables;
the second item emitted by the new Observable will be the result of
the function applied to the second item emitted by each of those
Observables; and so forth.
Due to Spring's widespread popularity, they try very hard to maintain backward compatibility and in doing so, sometimes make compromises with the API. AsyncRestTemplate methods returning ListenableFuture is one such case. If they committed to Java 8+, CompletableFuture could be used instead. Why? Since we won't be dealing with thread pools directly, we don't have a good way to know when all the ListenableFutures have completed. CompletableFuture has an allOf method that creates a new CompletableFuture that is completed when all of the given CompletableFutures complete. Since we don't have that in ListenableFuture, we will have to improvise.
I've not compiled the following code but it should be clear what I'm trying to do. I'm using Java 8 because it's end of 2016.
// Lombok FTW
#RequiredArgsConstructor
public final class CounterCallback implements ListenableFutureCallback<ResponseEntity<String>> {
private final LongAdder adder;
public void onFailure(Throwable ex) {
adder.increment();
}
public void onSuccess(ResponseEntity<String> result) {
adder.increment();
}
}
ListenableFuture<ResponseEntity<String>> f1 = asyncRestTemplate
.getForEntity(url1, String.class);
f1.addCallback(//);
// more futures
LongAdder adder = new LongAdder();
ListenableFutureCallback<ResponseEntity<String>> callback = new CounterCallback(adder);
Stream.of(f1, f2, f3)
.forEach {f -> f.addCallback(callback)}
for (int counter = 1; adder.sum() < 3 && counter < 10; counter++) {
Thread.sleep(1000);
}
// either all futures are done or we're done waiting
Map<Boolean, ResponseEntity<String>> futures = Stream.of(f1, f2, f3)
.collect(Collectors.partitioningBy(Future::isDone));
Now we've a Map for which futures.get(Boolean.TRUE) will give us all the futures that have completed and futures.get(Boolean.FALSE) will give us the ones that didn't. We will want to cancel the ones that didn't complete.
This code does a few things that are important with parallel programming:
It doesn't block.
It limits the operation to some maximum allowed time.
It clearly separates successful and failure cases.

Categories