Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
com.hubspot.singularity.async.CompletableFutures Maven / Gradle / Ivy
package com.hubspot.singularity.async;
import java.util.Collection;
import java.util.concurrent.Callable;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionStage;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.BiFunction;
import java.util.function.Supplier;
import java.util.stream.Collector;
import java.util.stream.Collectors;
import com.google.common.util.concurrent.ThreadFactoryBuilder;
import io.netty.util.HashedWheelTimer;
import io.netty.util.Timeout;
public class CompletableFutures {
private CompletableFutures() {}
public static CompletableFuture allOf(Collection> futures) {
return CompletableFuture.allOf(futures.toArray(new CompletableFuture[futures.size()]));
}
public static CompletableFuture anyOf(Collection> futures) {
return CompletableFuture.anyOf(futures.toArray(new CompletableFuture[futures.size()]));
}
public static CompletableFuture exceptionalFuture(Throwable t) {
CompletableFuture future = new CompletableFuture<>();
future.completeExceptionally(t);
return future;
}
/**
* Return a future that completes with a timeout after a delay.
*/
public static CompletableFuture timeoutFuture(HashedWheelTimer hwt, long delay, TimeUnit timeUnit) {
try {
CompletableFuture future = new CompletableFuture<>();
hwt.newTimeout(future::complete, delay, timeUnit);
return future;
} catch (Throwable t) {
return exceptionalFuture(t);
}
}
/**
* Useful for composing an async call in response to exceptional cases.
* For example:
* {@code
* return thenHandleCompose(myFuture, (success, th) -> {
* if (th != null) {
* return newCompletableFuture();
* } else {
* return CompletableFuture.completedFuture(success);
* }
* });
* }
*/
public static CompletableFuture thenHandleCompose(CompletionStage completionStage,
BiFunction super T, Throwable, ? extends CompletionStage> fn) {
return completionStage.handle((success, throwable) -> new SuccessOrThrowable<>(success, throwable))
.thenCompose(pair ->
fn.apply(pair.item, pair.ex)
).toCompletableFuture();
}
public static CompletableFuture thenHandleComposeAsync(CompletionStage completionStage,
BiFunction super T, Throwable, ? extends CompletionStage> fn,
ExecutorService executorService) {
return completionStage.handleAsync((success, throwable) -> new SuccessOrThrowable<>(success, throwable), executorService)
.thenComposeAsync(
pair -> fn.apply(pair.item, pair.ex),
executorService
).toCompletableFuture();
}
private static final HashedWheelTimer DEFAULT_TIMER = new HashedWheelTimer(
new ThreadFactoryBuilder().setDaemon(true).setNameFormat("futures-utils-%s").build()
);
public static CompletableFuture enforceTimeout(CompletionStage underlyingFuture,
long timeout,
TimeUnit timeUnit) {
return enforceTimeout(underlyingFuture, DEFAULT_TIMER, timeout, timeUnit);
}
public static CompletableFuture enforceTimeout(CompletionStage underlyingFuture,
long timeout,
TimeUnit timeUnit,
Supplier exceptionSupplier) {
return enforceTimeout(underlyingFuture, DEFAULT_TIMER, timeout, timeUnit, exceptionSupplier);
}
public static CompletableFuture enforceTimeout(CompletionStage underlyingFuture,
HashedWheelTimer timer,
long timeout,
TimeUnit timeUnit) {
return enforceTimeout(underlyingFuture, timer, timeout, timeUnit, TimeoutException::new);
}
public static CompletableFuture enforceTimeout(CompletionStage underlyingFuture,
HashedWheelTimer timer,
long timeout,
TimeUnit timeUnit,
Supplier exceptionSupplier) {
// We don't want to muck with the underlying future passed in, so
// chaining a .thenApply(x -> x) forces a new future to be created with its own
// completion tracking. In this way, the original future is left alone and can
// time out on its own schedule.
CompletableFuture future = underlyingFuture.thenApply(x -> x)
.toCompletableFuture();
Timeout hwtTimeout = timer.newTimeout(
(ignored) -> future.completeExceptionally(exceptionSupplier.get()),
timeout,
timeUnit
);
future.whenComplete((result, throwable) -> hwtTimeout.cancel());
return future;
}
public static CompletableFuture executeWithTimeout(Callable callable,
ExecutorService executorService,
long timeout,
TimeUnit timeUnit) {
return executeWithTimeout(callable, executorService, DEFAULT_TIMER, timeout, timeUnit);
}
public static CompletableFuture executeWithTimeout(Callable callable,
ExecutorService executorService,
HashedWheelTimer timer,
long timeout,
TimeUnit timeUnit) {
CompletableFuture future = new CompletableFuture<>();
AtomicReference timeoutRef = new AtomicReference<>();
Future underlying = executorService.submit(() -> {
if (future.complete(callable.call())) {
Timeout timeout1 = timeoutRef.get();
if (timeout1 != null) {
timeout1.cancel();
}
}
return null;
});
timeoutRef.set(timer.newTimeout((ignored) -> {
if (!future.isDone()) {
if (future.completeExceptionally(new TimeoutException())) {
underlying.cancel(true);
}
}
}, timeout, timeUnit));
return future;
}
public static T join(CompletableFuture future, long timeout, TimeUnit unit) {
try {
return future.get(timeout, unit);
} catch (InterruptedException | ExecutionException | TimeoutException e) {
throw new RuntimeException(e);
}
}
public static Collector, ?, CompletableFuture> collectAllOf() {
return Collectors.collectingAndThen(
Collectors.toList(),
CompletableFutures::allOf);
}
private static class SuccessOrThrowable {
private final T item;
private final Throwable ex;
public SuccessOrThrowable(T item, Throwable ex) {
this.item = item;
this.ex = ex;
}
}
}