-
Notifications
You must be signed in to change notification settings - Fork 306
Description
Among other things, we use Failsafe for uploading/downloading files via HTTP. In such cases, when the upload/download of a file is cancelled we want to stop not just Failsafe's retries but also the underlying file transfer. Our file transfer client returns a CompleteableFuture and thus we call FailsafeExecutor.getStageAsync(() -> uploadFile(...)). However, cancelling the returned CompletableFuture does not cancel the CompletableFuture returned by uploadFile(...). This is kind of obvious since getStageAsync() only works with CompletionStage but it would be great if Failsafe could also cancel the CompletableFutures returned by the passed supplier.
Here's a full example:
public class Demo {
public static void main(String[] args) {
CompletableFuture<String> future = computeSomethingWithRetries();
future.whenComplete((r, t) -> {
if (t instanceof CancellationException) {
System.out.println("Failsafe's CompletableFuture was cancelled");
}
});
future.cancel(true);
}
static CompletableFuture<String> computeSomethingWithRetries() {
Policy<String> retryPolicy = new RetryPolicy<String>()
.handle(RuntimeException.class)
.withMaxAttempts(-1);
return Failsafe.with(retryPolicy).getStageAsync(Demo::computeSomething);
}
static CompletableFuture<String> computeSomething() {
CompletableFuture<String> future = new CompletableFuture<>();
future.whenComplete((r, t) -> {
if (t instanceof CancellationException) {
System.out.println("Inner CompletableFuture was cancelled");
}
});
return future;
}
}This currently prints
Failsafe's CompletableFuture was cancelled
but should print
Inner CompletableFuture was cancelled
Failsafe's CompletableFuture was cancelled
Full Gradle project: https://github.com/marcphilipp/gradle-sandbox/tree/master/failsafe-completable-future