I want to skip chain of completablefutures based a specific condition. I tried the solution proposed at chaining several completionstage, but it doesn't seem to work. Here it the code:
@RunWith(JUnit4.class)
public class ExceptionHandlingTests {
@Test
public void test1() {
CompletableFuture<Integer> result = new CompletableFuture<>();
CompletableFuture.runAsync(() -> {
System.out.println("Completing result1. Result: " + result.isDone());
result.complete(10);
}).thenCompose(x -> {
System.out.println("Completing result2. Result: " + result.isDone());
result.complete(10);
return CompletableFuture.completedFuture(5);
}).thenCompose(x -> {
System.out.println("Completing result3. Result: " + result.isDone());
result.complete(10);
return CompletableFuture.completedFuture(5);
}).applyToEither(result, Function.identity());
}
}
Output:
Completing result1. Result: false
Completing result2. Result: true
Completing result3. Result: true
Even though the "result" completablefuture is marked completed, subsequent completablefutures are still executed. How to skip Completablefuture 2 and 3?
You have created a dependency chain like this:
first
↓ (↘)
next result
↓ ↙
final
The (↘)
is an explicit completion call result.complete(…)
, but all other completions happen automatically. The final
stage, created via applyToEither
will be completed with either of the prerequisites, whichever is completed first, but does not modify the behavior of them.
In principle, any code could invoke complete
on it without affecting either of these stages that might complete the final
stage otherwise. The same applies to cancellation. Calling cancel
on a stage will complete the stage, your calling the method on, without affecting the stages you used to construct it.
The answer of the linked question creates stages like
first
(↙) (↘)
next 1 result
↓ |
next 2 |
↘ ↙
final
The key point is, the initial stage will complete either of two CompletableFuture
s explicitly, not triggering an automatic completion. The other chain of dependent stages will never get evaluated. Since the final
stage is an applyToEither
, the completion of only one of the chains is sufficient to evaluate the final function. It still does not affect the prerequisite stages.
Note that for your chain, consisting of thenCompose
operations, you can implement a similar logic in a simpler fashion, due to the fact that your functions return a CompletableFuture
anyway. So simply returning a new CompletableFuture
that will never be completed when you want to shortcut, solves the issue. You can even rewrite your initial runAsync
to use thenCompose
instead:
for(int shortCutAt: IntStream.range(0, 4).toArray()) {
System.out.println("Example execution with "
+(shortCutAt==0? "no shortcut": "shortcut at "+shortCutAt));
CompletableFuture<Integer> result = new CompletableFuture<>();
CompletableFuture.completedFuture(null).thenCompose(justVoid -> { // runAsync
System.out.println("Completing result1. Result: " + result.isDone());
if(shortCutAt == 1) { result.complete(10); return new CompletableFuture<>(); }
return CompletableFuture.completedFuture(justVoid);
}).thenCompose(x -> {
System.out.println("Completing result2. Result: " + result.isDone());
if(shortCutAt == 2) { result.complete(10); return new CompletableFuture<>(); }
return CompletableFuture.completedFuture(5);
}).thenCompose(x -> {
System.out.println("Completing result3. Result: " + result.isDone());
if(shortCutAt == 3) { result.complete(10); return new CompletableFuture<>(); }
return CompletableFuture.completedFuture(5);
})
.applyToEither(result, Function.identity())
.thenAccept(fr -> System.out.println("final result: "+fr));
System.out.println();
}
Example execution with no shortcut
Completing result1. Result: false
Completing result2. Result: false
Completing result3. Result: false
final result: 5
Example execution with shortcut at 1
Completing result1. Result: false
final result: 10
Example execution with shortcut at 2
Completing result1. Result: false
Completing result2. Result: false
final result: 10
Example execution with shortcut at 3
Completing result1. Result: false
Completing result2. Result: false
Completing result3. Result: false
final result: 10
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With