Skip to content

Commit e6ae193

Browse files
lukasz-antoniakabsurdfarce
authored andcommitted
JAVA-3167: CompletableFutures.allSuccessful() may return never completed future
patch by Lukasz Antoniak; reviewed by Andy Tolbert, and Bret McGuire for JAVA-3167
1 parent 0962794 commit e6ae193

File tree

2 files changed

+33
-1
lines changed

2 files changed

+33
-1
lines changed

core/src/main/java/com/datastax/oss/driver/internal/core/util/concurrent/CompletableFutures.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,10 @@ public static <T> CompletionStage<Void> allSuccessful(List<CompletionStage<T>> i
100100
} else {
101101
Throwable finalError = errors.get(0);
102102
for (int i = 1; i < errors.size(); i++) {
103-
finalError.addSuppressed(errors.get(i));
103+
Throwable suppressedError = errors.get(i);
104+
if (finalError != suppressedError) {
105+
finalError.addSuppressed(suppressedError);
106+
}
104107
}
105108
result.completeExceptionally(finalError);
106109
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
package com.datastax.oss.driver.internal.core.util.concurrent;
2+
3+
import static org.assertj.core.api.Assertions.assertThat;
4+
5+
import java.util.Arrays;
6+
import java.util.concurrent.CompletableFuture;
7+
import java.util.concurrent.ExecutionException;
8+
import java.util.concurrent.TimeUnit;
9+
import org.junit.Test;
10+
11+
public class CompletableFuturesTest {
12+
@Test
13+
public void should_not_suppress_identical_exceptions() throws Exception {
14+
RuntimeException error = new RuntimeException();
15+
CompletableFuture<Void> future1 = new CompletableFuture<>();
16+
future1.completeExceptionally(error);
17+
CompletableFuture<Void> future2 = new CompletableFuture<>();
18+
future2.completeExceptionally(error);
19+
try {
20+
// if timeout exception is thrown, it indicates that CompletableFutures.allSuccessful()
21+
// did not complete the returned future and potentially caller will wait infinitely
22+
CompletableFutures.allSuccessful(Arrays.asList(future1, future2))
23+
.toCompletableFuture()
24+
.get(1, TimeUnit.SECONDS);
25+
} catch (ExecutionException e) {
26+
assertThat(e.getCause()).isEqualTo(error);
27+
}
28+
}
29+
}

0 commit comments

Comments
 (0)