Search in sources :

Example 1 with Timeout

use of dev.failsafe.Timeout 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 Timeout

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

the class Issue260Test method test.

public void test() throws Throwable {
    ExecutorService executor = Executors.newSingleThreadExecutor();
    Timeout<Object> timeout = Timeout.builder(Duration.ofMillis(300)).withInterrupt().onFailure(e -> System.out.println("Interrupted")).build();
    RetryPolicy<Object> rp = RetryPolicy.builder().onRetry(e -> System.out.println("Retrying")).onSuccess(e -> System.out.println("Success")).build();
    Function<Integer, ContextualRunnable> task = (taskId) -> ctx -> {
        System.out.println("Starting execution of task " + taskId);
        try {
            Thread.sleep(200);
        } catch (InterruptedException e) {
            System.out.println("Interrupted task " + taskId);
            throw e;
        }
    };
    Future<?> f1 = Failsafe.with(rp, timeout).with(executor).runAsync(task.apply(1));
    Future<?> f2 = Failsafe.with(rp, timeout).with(executor).runAsync(task.apply(2));
    Future<?> f3 = Failsafe.with(rp, timeout).with(executor).runAsync(task.apply(3));
    f1.get(1, TimeUnit.SECONDS);
    f2.get(1, TimeUnit.SECONDS);
    f3.get(1, TimeUnit.SECONDS);
}
Also used : TimeUnit(java.util.concurrent.TimeUnit) Future(java.util.concurrent.Future) RetryPolicy(dev.failsafe.RetryPolicy) Duration(java.time.Duration) Failsafe(dev.failsafe.Failsafe) Test(org.testng.annotations.Test) ContextualRunnable(dev.failsafe.function.ContextualRunnable) Timeout(dev.failsafe.Timeout) Function(java.util.function.Function) ExecutorService(java.util.concurrent.ExecutorService) Executors(java.util.concurrent.Executors) ContextualRunnable(dev.failsafe.function.ContextualRunnable) ExecutorService(java.util.concurrent.ExecutorService)

Example 3 with Timeout

use of dev.failsafe.Timeout 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)3 Future (java.util.concurrent.Future)3 TimeUnit (java.util.concurrent.TimeUnit)3 Function (java.util.function.Function)3 TimeoutConfig (dev.failsafe.TimeoutConfig)2 TimeoutExceededException (dev.failsafe.TimeoutExceededException)2 dev.failsafe.spi (dev.failsafe.spi)2 CompletableFuture (java.util.concurrent.CompletableFuture)2 AtomicReference (java.util.concurrent.atomic.AtomicReference)2 Failsafe (dev.failsafe.Failsafe)1 RetryPolicy (dev.failsafe.RetryPolicy)1 ContextualRunnable (dev.failsafe.function.ContextualRunnable)1 Duration (java.time.Duration)1 ExecutorService (java.util.concurrent.ExecutorService)1 Executors (java.util.concurrent.Executors)1 Test (org.testng.annotations.Test)1