Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to await a list of ListenableFuture with a timeout

Tags:

java

future

guava

I'm working on a problem where I have a List<ListenableFuture<T>>. I would like to aggregate the results of all of these futures into a List<T> with a timeout. The naive approach would be something like:

List<T> blockForResponses(List<ListenableFuture<T>> futures, long timeoutMillis) {
    return futures.stream()
        .map(future -> future.get(timeoutMillis,TimeUnit.MILLISECONDS)
        .collect(Collectors.toList());
}

This doesn't work because it waits for the timeout for each future and I want that to be the timeout for the entire list. Manually keeping track of how much time has passed also doesn't work because if the first one times out, there won't be any time left to try the others.

The solution I'm looking for would enforce a timeout on all of the futures and return when the timeout had elapsed or all of the futures in the list were complete. Then I could inspect each future in the list myself to aggregate the results and check which ones timed out.

like image 867
Daniel Avatar asked Dec 20 '18 21:12

Daniel


1 Answers

This problem turned out to be simpler than I thought. I was able to use the Futures.allAsList method and then catch the TimeoutException:

List<T> blockForResponses(List<ListenableFuture<T>> futures, long timeoutMillis) {
    ListenableFuture<List<T>> futureOfList = Futures.allAsList(futures);
    List<T> responses;
    try {
        responses = futureOfList.get(timeoutMillis, TimeUnit.MILLISECONDS);
    } catch (TimeoutException e) {
        responses = new ArrayList<>();
        for (ListenableFuture<T> future : futures) {
            if (future.isDone()) {
                responses.add(Uninterruptibles.getUninterruptibly(future));
            }
        }
    }
    return responses;
}
like image 189
Daniel Avatar answered Sep 28 '22 04:09

Daniel