Skip to content

Commit

Permalink
Fail fast implementation for joinList (#68)
Browse files Browse the repository at this point in the history
  • Loading branch information
JoseAlavez authored Jun 11, 2020
1 parent 0a318f8 commit fbb803f
Show file tree
Hide file tree
Showing 2 changed files with 35 additions and 2 deletions.
16 changes: 14 additions & 2 deletions src/main/java/com/spotify/futures/CompletableFutures.java
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ private CompletableFutures() {
* Returns a new {@link CompletableFuture} which completes to a list of all values of its input
* stages, if all succeed. The list of results is in the same order as the input stages.
*
* <p> If any of the given stages complete exceptionally, then the returned future also does so,
* <p> As soon as any of the given stages complete exceptionally, then the returned future also does so,
* with a {@link CompletionException} holding this exception as its cause.
*
* <p> If no stages are provided, returns a future holding an empty list.
Expand All @@ -75,7 +75,19 @@ public static <T> CompletableFuture<List<T>> allAsList(
for (int i = 0; i < stages.size(); i++) {
all[i] = stages.get(i).toCompletableFuture();
}
return CompletableFuture.allOf(all)

CompletableFuture<Void> allOf = CompletableFuture.allOf(all);

for (int i = 0; i < all.length; i++) {
all[i].exceptionally(throwable -> {
if (!allOf.isDone()) {
allOf.completeExceptionally(throwable);
}
return null; // intentionally unused
});
}

return allOf
.thenApply(ignored -> {
final List<T> result = new ArrayList<>(all.length);
for (int i = 0; i < all.length; i++) {
Expand Down
21 changes: 21 additions & 0 deletions src/test/java/com/spotify/futures/CompletableFuturesTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@
import java.util.concurrent.ScheduledFuture;
import java.util.function.Supplier;
import java.util.stream.Stream;
import java.util.concurrent.CompletionException;
import java.util.concurrent.TimeoutException;

import static com.spotify.futures.CompletableFutures.allAsList;
import static com.spotify.futures.CompletableFutures.allAsMap;
Expand Down Expand Up @@ -64,13 +66,15 @@
import static org.hamcrest.Matchers.contains;
import static org.hamcrest.Matchers.hasProperty;
import static org.hamcrest.Matchers.hasSize;
import static org.hamcrest.Matchers.instanceOf;
import static org.hamcrest.Matchers.nullValue;
import static org.hamcrest.core.Is.is;
import static org.hamcrest.core.Is.isA;
import static org.hamcrest.core.IsNot.not;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.fail;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyLong;
import static org.mockito.Matchers.eq;
Expand Down Expand Up @@ -125,6 +129,23 @@ public void allAsList_exceptional() throws Exception {
allAsList(input).get();
}

@Test
public void allAsList_exceptional_failFast() {
final CompletableFuture<String> incomplete = incompleteFuture();
final CompletableFuture<String> failed =
exceptionallyCompletedFuture(new TimeoutException());
final List<CompletionStage<String>> input =
asList(incomplete, failed);

try {
allAsList(input).join();
fail("Expected exception being thrown.");
} catch (Exception e) {
assertThat(e, instanceOf(CompletionException.class));
assertThat(e.getCause(), instanceOf(TimeoutException.class));
}
}

@Test
public void allAsList_null() throws Exception {
exception.expect(NullPointerException.class);
Expand Down

0 comments on commit fbb803f

Please sign in to comment.