How can I add futures by CompletableFuture.allOf() when the futures are created within a for-loop? I want to create a bunch of futures which should be executed in parallel. And only when all futures are completed the method should return the result:
// Version 1: execute each task in async and return alls tasks when finished
public Set<Task> getTasks(){
var executor = Executors.newCachedThreadPool();
var tasks = new LinkedHashSet<Task>();
var futures = new ArrayList<CompletableFuture<Set<Task>>>();
for (var task : user.getTasks()) {
// all futures are executed in parallel
futures.add(CompletableFuture.supplyAsync(() -> execute(task), executor));
}
for (var f : futures) {
// this will block as long as each future is finished
tasks.addAll(f.join());
}
return tasks;
}
Or is there another alternative? I have also tried the following, but it also executes the futures one after another (instead of parallel):
// Version 2:
var executor = Executors.newCachedThreadPool();
var tasks = new LinkedHashSet<Task>();
for (var task : user.getTasks()) {
CompletableFuture.supplyAsync(() -> execute(task), executor)
.thenAccept(tasks::addAll).join();
}
EDIT: at the end I have two versions which come close the problem I would like to solve. However, I guess version A is not right because parallel threads will add elements to the LinkedHashSet in async mode (which could cause trouble, because LinkedHashSet is not thread safe):
VERSION A (it seems not thread safe):
var executor = Executors.newCachedThreadPool();
var tasks = new LinkedHashSet<Task>();
var futures = new ArrayList<CompletableFuture<Void>>();
for (var t : user.getTasks()) {
futures.add(CompletableFuture.supplyAsync(() -> execute(t), executor).thenAcceptAsync(tasks::addAll));
}
CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join();
and VERSION B (which could be better, but is a little complex):
var executor = Executors.newCachedThreadPool();
var futures = new ArrayList<CompletableFuture<Set<Task>>>();
for (var t : user.getTasks()) {
futures.add(CompletableFuture.supplyAsync(() -> execute(t), executor));
}
Set<Task> o = CompletableFuture
.allOf(futures.toArray(new CompletableFuture[0]))
.thenApplyAsync(v -> futures.stream().flatMap(future -> future.join().stream()))
.join().collect(Collectors.toSet());
I cannot find an easier approach..but for completness, I add the following code which is the shortest - however, it uses ForkJoinPool which should be avoided (?) for long running tasks:
// VERSION C: execute in parallel without suffering from CompletableApi:
return user.getTasks()
.parallelStream()
.flatMap(t -> execute(t).stream())
.collect(Collectors.toSet());
Your code should work as it is. That is, the for loop in your first example waits for the first future to complete before proceeding to the second future, but in the meantime all the other futures are concurrently running. They typically start to execute as soon as you've called supplyAsync. To prove this, here's a self-contained executable:
import java.time.LocalTime;
import java.util.ArrayList;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
public class Demo {
public static void main(String[] args) throws InterruptedException {
var executor = Executors.newCachedThreadPool();
var results = new ArrayList<String>();
var futures = new ArrayList<CompletableFuture<String>>();
futures.add(CompletableFuture.supplyAsync(() -> sleep(2), executor));
TimeUnit.MILLISECONDS.sleep(100);
futures.add(CompletableFuture.supplyAsync(() -> sleep(1), executor));
// All futures are executed in parallel
for (var f : futures) {
results.add(f.join());
}
results.forEach(System.out::println);
}
private static String sleep(int seconds) {
var start = LocalTime.now();
try {
TimeUnit.SECONDS.sleep(seconds);
} catch (InterruptedException ignored) {
Thread.currentThread().interrupt();
}
var end = LocalTime.now();
return String.format("Thread %s started at %s and finished at %s",
Thread.currentThread().getId(), start, end);
}
}
The output proves that the second future finished before the first, as expected:
Thread 14 started at 17:49:35.202673531 and finished at 17:49:37.206196631
Thread 15 started at 17:49:35.262183490 and finished at 17:49:36.262342704
CompletableFuture.allOf() is pretty simple here when using Stream API:
CompletableFuture.allOf(user.getTasks().stream()
.map(task -> CompletableFuture.supplyAsync(() -> execute(task), executor))
.toArray(CompletableFuture[]::new))
.join();
Of course your second variant will execute one after another:
CompletableFuture.supplyAsync(() -> execute(task), executor)
.thenAccept(tasks::addAll)
.join();
You join that, blocking the thread.
The second problem is the use of newCachedThreadPool. I'll explain that based on the jdk's HttpClient. In the early version it had that in the documentation that it will use a cached pool, later they removed it from the documentation. Currently it is left in the implementation, but that will be removed also, in time. The problem is that such a pool, when you use it incorrectly, will eat all your resources and kill your application. No more free threads? Sure, I will create a new one, and so on... Eventually this will hurt you. Use a pool with a limited numbers of threads.
To answer your question, you are looking for some kind of flatMap, that could do CompletableFuture<Set<X>> to Set<CompletableFuture<X>>. Such a non-blocking method does not exist. You need to call join, but you can delay the call to that join via a trick:
user.getTasks().stream()
.map(each -> CompletableFuture.supplyAsync(() -> execute(each), executor))
.flatMap(x -> Stream.of(x).map(CompletableFuture::join))
.flatMap(Set::stream)
.collect(Collectors.toSet());
After trying all those versions above I come to the conclustion that the following solution is the best:
// VERSION X is the best
public Set<Task> getTasks(){
var executor = Executors.newCachedThreadPool();
var futures = new ArrayList<Future<Set<Task>>>();
var tasks = new LinkedHashSet<Task>();
for (var t : user.getTasks()) {
futures.add(executor.submit(() -> executor(t)));
}
for (var f : futures) {
try {
tasks.addAll(f.get());
} catch (Exception e) {
e.printStackTrace();
}
}
return tasks;
}
}
It's the best because:
easy and fast code (no unneeded overhead, lambdas, completableFuture,..)
no exception is surpressed
does not stop the execution of further tasks if one task raises an exception
If anyone can convince me to use other versions, then please add arguments.
I need to chain sequentially in order Vertx CompositeFutures in a RxJava style for dependent CompositeFuture, avoiding callback hell.
The use case:
Each CompositeFuture.any/all do some async operations that return futures, lets say myList1, myList2, myList3, but I must wait for CompositeFuture.any(myList1) to complete and return success before doing CompositeFuture.any(myList2), and the same from myList2 to myList3. Naturally, the CompositeFuture itself does the jobs async, but just for its set of operations, since the next set have to be done just after the first set goes well.
Doing it in a "callback-hell style" would be:
public static void myFunc(Vertx vertx, Handler<AsyncResult<CompositeFuture>> asyncResultHandler) {
CompositeFuture.any(myList1 < Future >)
.onComplete(ar1 -> {
if (!ar1.succeeded()) {
asyncResultHandler.handle(ar1);
} else {
CompositeFuture.any(myList2 < Future >)
.onComplete(ar2 -> {
if (!ar2.succeeded()) {
asyncResultHandler.handle(ar2);
} else {
CompositeFuture.all(myList3 < Future >)
.onComplete(ar3 -> {
asyncResultHandler.handle(ar3);
.... <ARROW OF CLOSING BRACKETS> ...
}
Now I tried somenthing like this:
public static void myFunc(Vertx vertx, Handler<AsyncResult<CompositeFuture>> asyncResultHandler) {
Single
.just(CompositeFuture.any(myList1 < Future >))
.flatMap(previousFuture -> rxComposeAny(previousFuture, myList2 < Future >))
.flatMap(previousFuture -> rxComposeAll(previousFuture, myList3 < Future >))
.subscribe(SingleHelper.toObserver(asyncResultHandler));
}
public static Single<CompositeFuture> rxComposeAny(CompositeFuture previousResult, List<Future> myList) {
if (previousResult.failed()) return Single.just(previousResult); // See explanation bellow
CompositeFuture compositeFuture = CompositeFuture.any(myList);
return Single.just(compositeFuture);
}
public static Single<CompositeFuture> rxComposeAll(CompositeFuture previousResult, List<Future> myList) {
if (previousResult.failed()) return Single.just(previousResult);
CompositeFuture compositeFuture = CompositeFuture.any(myList);
return Single.just(compositeFuture);
}
}
Much more compact and clear. But, I am not succeeding in passing the previous fails to the asyncResultHandler.
My idea was as follows: The flatMap passes the previous CompositeFuture result and I want to check if it failed. The next rxComposeAny/All first checks to see if previous failed, if so, just returns the failed CompositeFuture and so on until it hits the handler in the subscriber. If the previous passed the test, I`m ok to continue passing the current result till the last successful CompositeFuture hits the handler.
The problem is that the check
if (previousResult.failed()) return Single.just(previousResult); // See explanation bellow
doesn't work, and all the CompositeFutures are processed, but not tested for successful completion, just the last one ends up being passed to the asyncResultHandler which will test for overall failure (but in the case of my code, it ends up cheking just the last one)
I`m using Vertx 3.9.0 and RxJava 2 Vertx API.
Disclosure: I have experience in Vertx, but I'm totally new in RxJava. So I appreciate any answer, from technical solutions to conceptual explanations.
Thank you.
EDIT (after excellent response of #homerman):
I need to have the exact same behavior of the "callback hell style" of sequentially dependent CompositeFutures, ie, the next must be called after onComplete and test for completed with failure or success. The complexity comes from the fact that:
I have to use vertx CompositeAll/Any methods, not zip. Zip provides behaviour similar to CompositeAll, but not CompositeAny.
CompositeAll/Any return the completed future just inside onComplete method. If I check it before as showed above, since it is async, I will get unresolved futures.
CompositeAll/Any if failed will not throw error, but failed future inside onComplete, so I cannot use onError from rxJava.
For example, I tried the following change in the rxComposite function:
public static Single<CompositeFuture> rxLoadVerticlesAny(CompositeFuture previousResult, Vertx vertx, String deploymentName,
List<Class<? extends Verticle>> verticles, JsonObject config) {
previousResult.onComplete(event -> {
if (event.failed()) {
return Single.just(previousResult);
} else {
CompositeFuture compositeFuture = CompositeFuture.any(VertxDeployHelper.deploy(vertx, verticles, config));
return Single.just(compositeFuture);
}
}
);
}
But naturally it does not compile, since lambda is void. How can I reproduce this exact same behavior it rxJava in Vertx?
Just to clarify something...
Each CompositeFuture.any/all do some async operations that return
futures, lets say myList1, myList2, myList3, but I must wait for
CompositeFuture.any(myList1) to complete and return success before
doing CompositeFuture.any(myList2), and the same from myList2 to
myList3.
You've offered CompositeFuture.any() and CompositeFuture.all() as points of reference, but the behavior you describe is consistent with all(), which is to say the resulting composite will yield success only if all its constituents do.
For the purpose of my answer, I'm assuming all() is the behavior you expect.
In RxJava, an unexpected error triggered by an exception will result in termination of the stream with the underlying exception being delivered to the observer via the onError() callback.
As a small demo, assume the following setup:
final Single<String> a1 = Single.just("Batch-A-Operation-1");
final Single<String> a2 = Single.just("Batch-A-Operation-2");
final Single<String> a3 = Single.just("Batch-A-Operation-3");
final Single<String> b1 = Single.just("Batch-B-Operation-1");
final Single<String> b2 = Single.just("Batch-B-Operation-2");
final Single<String> b3 = Single.just("Batch-B-Operation-3");
final Single<String> c1 = Single.just("Batch-C-Operation-1");
final Single<String> c2 = Single.just("Batch-C-Operation-2");
final Single<String> c3 = Single.just("Batch-C-Operation-3");
Each Single represents a discrete operation to be performed, and they are logically named according to some logical grouping (ie they are meant to be executed together). For example, "Batch-A" corresponds to your "myList1", "Batch-B" to your "myList2", ...
Assume the following stream:
Single
.zip(a1, a2, a3, (s, s2, s3) -> {
return "A's completed successfully";
})
.flatMap((Function<String, SingleSource<String>>) s -> {
throw new RuntimeException("B's failed");
})
.flatMap((Function<String, SingleSource<String>>) s -> {
return Single.zip(c1, c2, c3, (one, two, three) -> "C's completed successfully");
})
.subscribe(
s -> System.out.println("## onSuccess(" + s + ")"),
t -> System.out.println("## onError(" + t.getMessage() + ")")
);
(If you're not familiar, the zip() operator can be used to combine the results of all the sources supplied as input to emit another/new source).
In this stream, because the processing of the B's ends up throwing an exception:
the stream is terminated during the execution of the B's
the exception is reported to the observer (ie the onError() handler is triggered)
the C's are never processed
If what you want, however, is to decide for yourself whether or not to execute each branch, one approach you could take is to pass the results from previous operations down the stream using some sort of state holder, like so:
class State {
final String value;
final Throwable error;
State(String value, Throwable error) {
this.value = value;
this.error = error;
}
}
The stream could then be modified to conditionally execute different batches, for example:
Single
.zip(a1, a2, a3, (s, s2, s3) -> {
try {
// Execute the A's here...
return new State("A's completed successfully", null);
} catch(Throwable t) {
return new State(null, t);
}
})
.flatMap((Function<State, SingleSource<State>>) s -> {
if(s.error != null) {
// If an error occurred upstream, skip this batch...
return Single.just(s);
} else {
try {
// ...otherwise, execute the B's
return Single.just(new State("B's completed successfully", null));
} catch(Throwable t) {
return Single.just(new State(null, t));
}
}
})
.flatMap((Function<State, SingleSource<State>>) s -> {
if(s.error != null) {
// If an error occurred upstream, skip this batch...
return Single.just(s);
} else {
try {
// ...otherwise, execute the C's
return Single.just(new State("C's completed successfully", null));
} catch(Throwable t) {
return Single.just(new State(null, t));
}
}
})
.subscribe(
s -> {
if(s.error != null) {
System.out.println("## onSuccess with error: " + s.error.getMessage());
} else {
System.out.println("## onSuccess without error: " + s.value);
}
},
t -> System.out.println("## onError(" + t.getMessage() + ")")
);
After some research in Vertx source code, I found a public method that the rx version of CompositeFuture uses to convert 'traditional' CompositeFuture to its rx version. The method is io.vertx.reactivex.core.CompositeFuture.newInstance. With this workaround, I could use my traditional method and then convert it to use in the rx chain. This was what I wanted, because it was problematic to change the existing traditional method.
Here is the code with comments:
rxGetConfig(vertx)
.flatMap(config -> {
return rxComposeAny(vertx, config)
.flatMap(r -> rxComposeAny(vertx, config))
.flatMap(r -> rxComposeAll(vertx, config));
})
.subscribe(
compositeFuture -> {
compositeFuture.onSuccess(event -> startPromise.complete());
},
error -> startPromise.fail(error));
public static Single<JsonObject> rxGetConfig(Vertx vertx) {
ConfigRetrieverOptions enrichConfigRetrieverOptions = getEnrichConfigRetrieverOptions();
// the reason we create new vertx is just to get an instance that is rx
// so this ConfigRetriever is from io.vertx.reactivex.config, instead of normal io.vertx.config
ConfigRetriever configRetriever = ConfigRetriever.create(io.vertx.reactivex.core.Vertx.newInstance(vertx), enrichConfigRetrieverOptions);
return configRetriever.rxGetConfig();
}
public static Single<io.vertx.reactivex.core.CompositeFuture> rxComposeAny(Vertx vertx, JsonObject config) {
// instead of adapted all the parameters of myMethodsThatReturnsFutures to be rx compliant,
// we create it 'normally' and the converts bellow to rx CompositeFuture
CompositeFuture compositeFuture = CompositeFuture.any(myMethodsThatReturnsFutures(config));
return io.vertx.reactivex.core.CompositeFuture
.newInstance(compositeFuture)
.rxOnComplete();
}
Although I've been writing Java code for many years, I've barely done any work with RxJava, and I need to understand how to map it to expected results. I have a lot of existing code in services I work with, but I'm not convinced they are using RxJava properly.
Note that we're using an old version of RxJava, 2.1.10. I can't upgrade at this moment.
The following is a common pattern I see in our codebase:
Single<ResultType> result1 = Single.<ResultType>create(source -> {
source.onSuccess(method1(parameters));
}).subscribeOn(Schedulers.io());
Single<ReturnType> result2 = Single.<ResultType>create(source -> {
source.onSuccess(method2(parameters));
}).subscribeOn(Schedulers.io());
if (null != result1 && null != result2) {
The intent of this is that the execution of "method1" and "method2" run in parallel, and that the check for "null != result1 && null != result2" happens after both methods have finished executing. I'm thinking it's possible that neither of these intentions are being fulfilled here, but I need confirmation of that, and also how to achieve those goals properly.
Depending on how your sources are setup, you can use combineLatest() to wait for the result from both sources. A sample proof-of-concept code might look like this:
public static void main(String[] args) throws Exception {
Callable<Integer> c1 = new Callable<Integer>() {
#Override
public Integer call() throws Exception {
System.out.println(System.currentTimeMillis()+"|Starting first");
Thread.sleep(1111);
System.out.println(System.currentTimeMillis()+"|finished first");
return 42;
}};
Single<Integer> singleFirst = Single.fromCallable(c1).subscribeOn(Schedulers.newThread());
Callable<Integer> c2 = new Callable<Integer>() {
#Override
public Integer call() throws Exception {
System.out.println(System.currentTimeMillis()+"|Starting second");
Thread.sleep(5555);
System.out.println(System.currentTimeMillis()+"|finished second");
return 12;
}};
Single<Integer> singleSecond = Single.fromCallable(c2).subscribeOn(Schedulers.newThread());
BiFunction<Integer, Integer, Integer> func = (a,b) -> a+b;
ObservableSource<Integer> source1 = singleFirst.toObservable();
ObservableSource<Integer> source2 = singleSecond.toObservable();
Observable<Integer> resultSource = Observable.combineLatest(source1, source2, func);
System.out.println(System.currentTimeMillis()+"|All setup, wait for completion");
resultSource.blockingSubscribe(r -> {
System.out.println(System.currentTimeMillis()+"|Result is: "+r);
});
}
This might generate the following output:
1589229378890|All setup, wait for completion
1589229378895|Starting second
1589229378895|Starting first
1589229380007|finished first
1589229384451|finished second
1589229384452|Result is: 54
As you see the Single subscriptions run in parallel and their values are "collected" in a combineLatest() call at the end.
I am new to the concept of CompletableFuture in Java, so I don't know a whole lot about it and its functions other than thenApply
I have a requirement where I have to test some condition in the thenApply block of a CompletableFuture A. If the condition is satisfied, return null, else return another CompletableFuture B so that in the next thenApply, the result will be that of B.
Basically I am trying to do something like the following:
CompletableFuture<String> A = ......
CompletableFuture<Boolean> B = ......
A.thenApply((res) -> {
if (res.equals("hey")) {
return null;
} else {
return B;
}
})
.thenApply((bResult) -> { // At this point, I want it to act as if I was calling B.thenApply
//some function;
})
Is this possible? Can I return a CompletableFuture from another CompletableFuture so that the next thenApply on the chain will actually be a thenApply of the returned CompletableFuture?
Also, if I want to cancel the next thenApplys on some condition. How do I do that?
I knew about:
retryWhen(...) that allow us to retry on error
and repeatWhen(...) that allow retrying on complete
Is there any operator like this:
return Observable.just(isUpdating)
.repeatWhenOnNext(isUpdating -> {
if(isUpdating) {
return Observable.timer(2, TimeUnit.SECONDS); // repeat after two seconds
} else {
return Observable.just(isUpdating); // flow down to concatMap
}
})
.concatMap(o -> doSomeWorkONLYWhenIsNotUpdating());
Hmm... No, but maybe this will do:
return Observable
.interval(0, 2, TimeUnit.SECONDS)
.filter(dummy -> !isUpdating)
.take(1)
.flatM(dummy -> doSomeWorkONLYWhenIsNotUpdating());