Press "Enter" to skip to content

CompletableFuture Timeouts in Java

As far as I love Java 8’s CompletableFuture, it has its downsides – idiomatic handling of timeouts is one of them.

Luckily, JDK 9 brought two new methods that provide the functionality everyone longed for – which is crucial for ensuring the proper resiliency when working with asynchronous processing.

In this super-short article, I will try to raise the awareness of the new crucial API methods.

CompletableFuture#orTimeout

Simply put, after calling the above method. The future will throw an ExecutionException if it doesn’t complete within a specified timeout.

A simple example:

CompletableFuture<Integer> future = CompletableFuture.supplyAsync(this::computeEndlessly)
  .orTimeout(1, TimeUnit.SECONDS);

future.get(); // java.util.concurrent.ExecutionException after waiting for 1 second

CompletableFuture#completeOnTimeout

In this option, we can return a default value once the timeout is reached:

CompletableFuture<Integer> future = CompletableFuture.supplyAsync(this::computeEndlessly)
  .completeOnTimeout(42, 1, TimeUnit.SECONDS);

Integer result = future.get(); // 42

As simple as that, although I don’t necessarily like the fact that we’re always forced to precompute the default value. If you look at the signature, you will see, that the value isn’t computed lazily:

public CompletableFuture<T> completeOnTimeout(T value, long timeout, TimeUnit unit)

This could’ve been easily achieved, for example, by providing an alternative API method that accepted Supplier<T> instead of plain Tmore about the idea can be found here.

Keep in mind that CompletableFutures are not bound to threads executing these jobs, so if even though CompletableFuture timeouts, the underlying task is still running in the background.

Sources

The complete example can be found on GitHub.




If you enjoyed the content, consider supporting the site:

Support the siteSupport the site