private <ReturnType> void executeNowIfNeeded(Collection<CompletableFuture<?>> existingTasks, Supplier<CompletableFuture<? extends ReturnType>> toRun, CompletableFuture<ReturnType> result) { if (existingTasks.isEmpty()) { // There were no previously running tasks for any of the given keys. Need to trigger its execution now, // outside of the synchronized block. Futures.completeAfter(toRun, result); } }
void complete(long segmentId) { Futures.completeAfter(() -> this.callback.apply(segmentId), this.result); }
private <ReturnType> void executeAfterIfNeeded(Collection<CompletableFuture<?>> existingTasks, Supplier<CompletableFuture<? extends ReturnType>> toRun, CompletableFuture<ReturnType> result) { if (!existingTasks.isEmpty()) { // Another task is in progress for at least one key that concerns us. Queue up behind them, and make sure to // only start the execution once all of those tasks are done. CompletableFuture.allOf(existingTasks.toArray(new CompletableFuture[existingTasks.size()])) .whenCompleteAsync((r, ex) -> Futures.completeAfter(toRun, result), this.executor); } }
/** * Executes one iteration of the MetadataCleaner. This ensures that there cannot be more than one concurrent executions of * such an iteration (whether it's from this direct call or from the regular MetadataCleaner invocation). If concurrent * invocations are made, then subsequent calls will be tied to the execution of the first, and will all complete at * the same time (even though there's only one executing). * * @return A CompletableFuture that, when completed, indicates that the operation completed (successfully or not). */ CompletableFuture<Void> runOnce() { CompletableFuture<Void> result; synchronized (this.singleRunLock) { if (this.currentIteration != null) { // Some other iteration is in progress. Piggyback on that one and return when it is done. return this.currentIteration; } else { // No other iteration is running. this.currentIteration = new CompletableFuture<>(); this.currentIteration.whenComplete((r, ex) -> { // Unregister the current iteration when done. synchronized (this.singleRunLock) { this.currentIteration = null; } }); result = this.currentIteration; } } Futures.completeAfter(this::runOnceInternal, result); return result; }
existingTask.whenCompleteAsync((r, ex) -> Futures.completeAfter(toRun, result), this.executor); Futures.completeAfter(toRun, result);
Futures.completeAfter(() -> processInternal(toProcess.data), toProcess.result);
private void createWritersInternal(EventStreamClientFactory clientFactory, final int writers, String scope, String stream, CompletableFuture<Void> writersComplete) { testState.writersListComplete.add(writersComplete); log.info("Client factory details {}", clientFactory.toString()); log.info("Creating {} writers", writers); List<CompletableFuture<Void>> writerFutureList = new ArrayList<>(); log.info("Writers writing in the scope {}", scope); CompletableFuture.runAsync(() -> { for (int i = 0; i < writers; i++) { log.info("Starting writer{}", i); final EventStreamWriter<String> tmpWriter = instantiateWriter(clientFactory, stream); final CompletableFuture<Void> writerFuture = startWriting(tmpWriter); Futures.exceptionListener(writerFuture, t -> log.error("Error while writing events:", t)); writerFutureList.add(writerFuture); } }, executorService).thenRun(() -> { testState.writers.addAll(writerFutureList); Futures.completeAfter(() -> Futures.allOf(writerFutureList), writersComplete); Futures.exceptionListener(writersComplete, t -> log.error("Exception while waiting for writers to complete", t)); }); }
Futures.completeAfter(() -> Futures.failedFuture(new IntentionalException()), toFail1); Assert.assertTrue("Async exceptions were not propagated properly (before).", toFail1.isCompletedExceptionally()); AssertExtensions.assertThrows( Futures.completeAfter(() -> sourceToFail2, toFail2); sourceToFail2.completeExceptionally(new IntentionalException()); Assert.assertTrue("Async exceptions were not propagated properly (after).", toFail2.isCompletedExceptionally()); AssertExtensions.assertThrows( "Sync exception did not get rethrown.", () -> Futures.completeAfter(() -> { throw new IntentionalException(); }, toFail3), Futures.completeAfter(() -> CompletableFuture.completedFuture(1), toComplete1); Assert.assertTrue("Normal completion did not happen (before).", Futures.isSuccessful(toComplete1)); Assert.assertEquals("Unexpected value from normal completion (before).", 1, (int) toComplete1.join()); Futures.completeAfter(() -> sourceToComplete2, toComplete2); sourceToComplete2.complete(2); Assert.assertTrue("Normal completion did not happen (after).", Futures.isSuccessful(toComplete2));
Futures.completeAfter(() -> Futures.allOf(readerFutureList), testState.readersComplete); Futures.exceptionListener(testState.readersComplete, t -> log.error("Exception while waiting for all readers to complete", t));