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;
};
}
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());
};
}
Aggregations