Search code examples
javamultithreadingasynchronousfuturecompletable-future

Interrupt underlying execution of CompletableFuture


I havw this piece of code:

 CompletableFuture<Void> timeoutFuture = CompletableFuture.allOf(futures.toArray(new CompletableFuture[0]))
                .orTimeout(1, TimeUnit.SECONDS); // Set a timeout for all futures combined

        CompletableFuture<List<MysticPlanetsNatalChartAspectResponse>> resultFuture = timeoutFuture
                .thenApply(v -> futures.stream()
                        .map(CompletableFuture::join)
                        .collect(Collectors.toList()));

        // Cancel any remaining futures that may not have completed
        futures.forEach(future -> {
            if (!future.isDone() && !future.isCancelled()) {
                try {
                    future.cancel(true);
                } catch (Throwable c) {
                    //System.out.println(c.getMessage());
                }
            }
        });

but the Exception is not catched and i see it in the console:

2023-09-18T21:38:43,869+02:00 [http-nio-8080-exec-1] ERROR o.a.c.c.C.[.[.[.[dispatcherServlet] - Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed: java.util.concurrent.CompletionException: java.util.concurrent.CancellationException] with root cause
java.util.concurrent.CancellationException: null

Solution

  • You can catch the exception using a lambda expression in the .map() method, and then filter the null values of the list, this way:

    CompletableFuture<List<MysticPlanetsNatalChartAspectResponse>> resultFuture = timeoutFuture
                    .thenApply(v -> futures.stream()
                            .map(future -> {
                                try {
                                    return future.join();
                                } catch (CompletionException | CancellationException ex) {
                                    // Handle the exception here
                                    return null;
                                }
                            })
                            // Filter out null results
                            .filter(Objects::nonNull) 
                            .collect(Collectors.toList()));