Search in sources :

Example 1 with TimeoutExceededException

use of dev.failsafe.TimeoutExceededException in project failsafe by jhalterman.

the class TimeoutExecutor method applyAsync.

/**
 * Schedules a separate timeout call that blocks and fails with {@link TimeoutExceededException} if the policy's
 * timeout is exceeded.
 * <p>
 * This implementation sets up a race between a timeout being triggered and the execution completing. Whichever
 * completes first will be the result that's recorded and used to complete the resulting promise.
 */
@Override
@SuppressWarnings("unchecked")
public Function<AsyncExecutionInternal<R>, CompletableFuture<ExecutionResult<R>>> applyAsync(Function<AsyncExecutionInternal<R>, CompletableFuture<ExecutionResult<R>>> innerFn, Scheduler scheduler, FailsafeFuture<R> future) {
    return execution -> {
        // Coordinates a race between the timeout and execution threads
        AtomicReference<ExecutionResult<R>> resultRef = new AtomicReference<>();
        AtomicReference<Future<R>> timeoutFutureRef = new AtomicReference<>();
        CompletableFuture<ExecutionResult<R>> promise = new CompletableFuture<>();
        // Guard against race with AsyncExecution.record, AsyncExecution.complete, future.complete or future.cancel
        synchronized (future) {
            // Schedule timeout if we are not done and not recording a result
            if (!future.isDone() && !execution.isRecorded()) {
                try {
                    Future<R> timeoutFuture = (Future<R>) Scheduler.DEFAULT.schedule(() -> {
                        // Guard against race with execution completion
                        ExecutionResult<R> cancelResult = ExecutionResult.exception(new TimeoutExceededException(policy));
                        if (resultRef.compareAndSet(null, cancelResult)) {
                            // Cancel and interrupt
                            execution.record(cancelResult);
                            execution.cancel(this);
                            future.cancelDependencies(this, config.canInterrupt(), cancelResult);
                        }
                        return null;
                    }, config.getTimeout().toNanos(), TimeUnit.NANOSECONDS);
                    timeoutFutureRef.set(timeoutFuture);
                    // Propagate outer cancellations to the Timeout future and its promise
                    future.setCancelFn(this, (mayInterrupt, cancelResult) -> {
                        timeoutFuture.cancel(mayInterrupt);
                        resultRef.compareAndSet(null, cancelResult);
                    });
                } catch (Throwable t) {
                    // Hard scheduling failure
                    promise.completeExceptionally(t);
                    return promise;
                }
            }
        }
        // Propagate execution, cancel timeout future if not done, and postExecute result
        innerFn.apply(execution).whenComplete((result, error) -> {
            if (error != null) {
                promise.completeExceptionally(error);
                return;
            }
            // Fetch timeout result if any
            if (!resultRef.compareAndSet(null, result))
                result = resultRef.get();
            if (result != null) {
                // Cancel timeout task
                Future<R> timeoutFuture = timeoutFutureRef.get();
                if (timeoutFuture != null && !timeoutFuture.isDone())
                    timeoutFuture.cancel(false);
                postExecuteAsync(execution, result, scheduler, future);
            }
            promise.complete(result);
        });
        return promise;
    };
}
Also used : TimeUnit(java.util.concurrent.TimeUnit) Future(java.util.concurrent.Future) dev.failsafe.spi(dev.failsafe.spi) TimeoutExceededException(dev.failsafe.TimeoutExceededException) CompletableFuture(java.util.concurrent.CompletableFuture) Timeout(dev.failsafe.Timeout) TimeoutConfig(dev.failsafe.TimeoutConfig) AtomicReference(java.util.concurrent.atomic.AtomicReference) Function(java.util.function.Function) CompletableFuture(java.util.concurrent.CompletableFuture) TimeoutExceededException(dev.failsafe.TimeoutExceededException) Future(java.util.concurrent.Future) CompletableFuture(java.util.concurrent.CompletableFuture) AtomicReference(java.util.concurrent.atomic.AtomicReference)

Example 2 with TimeoutExceededException

use of dev.failsafe.TimeoutExceededException in project failsafe by jhalterman.

the class TimeoutExecutor method apply.

/**
 * Schedules a separate timeout call that fails with {@link TimeoutExceededException} if the policy's timeout is
 * exceeded.
 * <p>
 * This implementation sets up a race between a timeout being triggered and the execution completing. Whichever
 * completes first will be the result that's recorded.
 */
@Override
public Function<SyncExecutionInternal<R>, ExecutionResult<R>> apply(Function<SyncExecutionInternal<R>, ExecutionResult<R>> innerFn, Scheduler scheduler) {
    return execution -> {
        // Coordinates a result between the timeout and execution threads
        AtomicReference<ExecutionResult<R>> result = new AtomicReference<>();
        Future<?> timeoutFuture;
        try {
            // Schedule timeout check
            timeoutFuture = Scheduler.DEFAULT.schedule(() -> {
                // Guard against race with execution completion
                ExecutionResult<R> cancelResult = ExecutionResult.exception(new TimeoutExceededException(policy));
                if (result.compareAndSet(null, cancelResult)) {
                    // Cancel and interrupt
                    execution.record(cancelResult);
                    execution.cancel(this);
                    if (config.canInterrupt())
                        execution.interrupt();
                }
                return null;
            }, config.getTimeout().toNanos(), TimeUnit.NANOSECONDS);
        } catch (Throwable t) {
            // Hard scheduling failure
            return postExecute(execution, ExecutionResult.exception(t));
        }
        // Propagate execution, cancel timeout future if not done, and postExecute result
        if (result.compareAndSet(null, innerFn.apply(execution)))
            timeoutFuture.cancel(false);
        return postExecute(execution, result.get());
    };
}
Also used : TimeUnit(java.util.concurrent.TimeUnit) Future(java.util.concurrent.Future) dev.failsafe.spi(dev.failsafe.spi) TimeoutExceededException(dev.failsafe.TimeoutExceededException) CompletableFuture(java.util.concurrent.CompletableFuture) Timeout(dev.failsafe.Timeout) TimeoutConfig(dev.failsafe.TimeoutConfig) AtomicReference(java.util.concurrent.atomic.AtomicReference) Function(java.util.function.Function) TimeoutExceededException(dev.failsafe.TimeoutExceededException) Future(java.util.concurrent.Future) CompletableFuture(java.util.concurrent.CompletableFuture) AtomicReference(java.util.concurrent.atomic.AtomicReference)

Aggregations

Timeout (dev.failsafe.Timeout)2 TimeoutConfig (dev.failsafe.TimeoutConfig)2 TimeoutExceededException (dev.failsafe.TimeoutExceededException)2 dev.failsafe.spi (dev.failsafe.spi)2 CompletableFuture (java.util.concurrent.CompletableFuture)2 Future (java.util.concurrent.Future)2 TimeUnit (java.util.concurrent.TimeUnit)2 AtomicReference (java.util.concurrent.atomic.AtomicReference)2 Function (java.util.function.Function)2