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.
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;
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With