Skip to content
AITroveRead. Build. Understand.
Make this comfortable

Java exceptionallyCompose: recover with another asynchronous stage

Last updated: 5 Oct 20265 min read
tutorial
AdvancedBy AITrove Editorial

CompletableFuture.exceptionallyCompose replaces an exceptional outcome with a new CompletionStage, allowing recovery that itself finishes asynchronously.

Operational contract

A primary receipt lookup can fail into a secondary lookup supplied by the caller. The callback may receive a CompletionException wrapper, so classification should inspect causes under a deliberate policy. This sample only retries an unavailable primary; validation failures and cancellation remain failures. The secondary future is created only after failure. Java 17 is the declared baseline for this lesson, and the method is available there. A fallback also needs its own deadline and resource budget.

Failure case

A primary read fails with a transient depot-unavailable exception. The backup read begins. If the primary fails because the receipt ID is malformed, the original failure is preserved instead of issuing a pointless backup request.

Java code

Java
import java.util.Objects;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionException;
import java.util.function.Supplier;

public class ReceiptReplicaFallback {
    public static class DepotUnavailable extends RuntimeException {
        public DepotUnavailable(String message) { super(message); }
    }

    public static CompletableFuture<String> recover(
            CompletableFuture<String> primary,
            Supplier<CompletableFuture<String>> backup) {
        Objects.requireNonNull(primary);
        Objects.requireNonNull(backup);
        return primary.exceptionallyCompose(failure -> {
            Throwable cause = failure instanceof CompletionException && failure.getCause() != null
                    ? failure.getCause() : failure;
            if (!(cause instanceof DepotUnavailable))
                return CompletableFuture.failedFuture(cause);
            return Objects.requireNonNull(backup.get(), "Backup stage missing");
        });
    }
}

Performance and ownership cost

Successful primary requests pay O(1) stage bookkeeping and no backup work. A qualifying failure incurs the secondary request's full latency and resource cost. A fallback that fans out repeatedly can amplify load during an outage.

Common Mistakes

  • Do not route cancellation or invalid input to a backup automatically.
  • Do not forget that a backup stage can fail or never complete.
  • Do not implement unbounded recursive recovery during an outage.

Connected lessons

java
race and recovery
completablefuture-exceptionallycompose-fallback
Storage details