Detect timeouts in a CompletableFuture chain

Viewed 193

Is there any possible safe way to detect timeouts in a CompletableFuture chain?

O someValue = CompletableFuture.supplyAsync(() -> {
                ...
                // API Call
                ...
            }).thenApply(o -> {
                ...
            }).thenApply(o -> {
                // If the chain has timed out, I still have 'o' ready here
                // So at least cache it here, so it's available for the next request
                // Even though the current request will return with a 'null'
                ...
            }).get(10, TimeUnit.SECONDS);
// cache 'someValue'
return someValue;

It completes successfully without a timeout, I can use 'someValue' and do whatever with it

If it times out, it throws a TimeoutException and I have lost the value, even though it's still being processed in the background

The idea is that even if it times out and since the API call in the thread still completes in the background and returns the response, I can use that value, let's say, for caching

1 Answers

Not at least in the way you show. When the exception is thrown, you lose any chance of getting your hands on the results of the API call even if it finishes. Your only chances of caching in a chain like that would be something like the following, which would not help with the time-outing API call itself

.thenApplyAsync(o -> {
    cache = o;
    // do something
}).thenApplyAsync(o -> {
    cache = o;
    // do something more
}).get(10, TimeUnit.SECONDS);

However reading through this gave me an idea, that what if you did something like the following

SynchronousQueue<Result> q = new SynchronousQueue<>();
CompletableFuture.supplyAsync(() -> {
    // API call
}.thenAccept(result -> {
    cache.put(result);   // cache the value
    q.offer(result); // offer value to main thread, if still there
}
);

// Main thread waits 10 seconds for a value to be asynchronously offered into the queue
// In case of timeout, null is returned, but any operations done
// before q.offer(result) are still performed

return queue.poll(10, TimeUnit.SECONDS);

An API call that doesn't finish in 10 seconds is still processed into cache as it is asynchronously accepted and the timeout happens in the main thread and not the CompletableFuture chain, even though the original request won't get the results (and I guess has to deal with it gracefully).

Related