/** * Returns a an ExecutionResult with the {@code failure} set, {@code completed} true and {@code success} false. */ public static ExecutionResult failure(Throwable failure) { return new ExecutionResult(null, failure, false, 0, true, false, false); }
@Override @SuppressWarnings("unchecked") protected ExecutionResult onFailure(ExecutionResult result) { try { return result.withResult(policy.apply(result.getResult(), result.getFailure(), execution.copy())); } catch (Exception e) { return ExecutionResult.failure(e); } }
private void callSuccessListener(ExecutionResult result) { if (result.isComplete() && policy instanceof FailurePolicy) { FailurePolicy failurePolicy = (FailurePolicy) policy; if (failurePolicy.successListener != null) failurePolicy.successListener.handle(result, execution); } }
/** * Records an execution attempt. * * @throws IllegalStateException if the execution is already complete */ void record(ExecutionResult result) { Assert.state(!completed, "Execution has already been completed"); attempts++; lastResult = result.getResult(); lastFailure = result.getFailure(); }
/** * Returns whether the {@code result} is a success according to the policy. If the {code result} has no result, it is * not a failure. */ protected boolean isFailure(ExecutionResult result) { if (result.isNonResult()) return false; else if (policy instanceof FailurePolicy) return ((FailurePolicy) policy).isFailure(result); else return result.getFailure() != null; }
static <T> Supplier<ExecutionResult> resultSupplierOf(CheckedSupplier<T> supplier, AbstractExecution execution) { return () -> { ExecutionResult result = null; try { result = ExecutionResult.success(supplier.get()); } catch (Throwable t) { result = ExecutionResult.failure(t); } finally { execution.record(result); } return result; }; }
if (delayFunction != null && policy.canApplyDelayFn(result.getResult(), result.getFailure())) { Duration computedDelay = delayFunction.computeDelay(result.getResult(), result.getFailure(), execution); if (computedDelay != null && computedDelay.toNanos() >= 0) computedDelayNanos = computedDelay.toNanos(); boolean maxDurationExceeded = policy.getMaxDuration() != null && elapsedNanos > policy.getMaxDuration().toNanos(); retriesExceeded = maxRetriesExceeded || maxDurationExceeded; boolean isAbortable = policy.isAbortable(result.getResult(), result.getFailure()); boolean shouldRetry = !result.isSuccess() && !isAbortable && !retriesExceeded && policy.allowsRetries(); boolean completed = isAbortable || !shouldRetry; boolean success = completed && result.isSuccess() && !isAbortable; retriesExceededListener.handle(result, execution); return result.with(waitNanos, completed, success);
@Override protected Supplier<ExecutionResult> supply(Supplier<ExecutionResult> supplier) { return () -> { while (true) { ExecutionResult result = supplier.get(); if (retriesExceeded) return result; result = postExecute(result); if (result.isComplete()) return result; try { Thread.sleep(TimeUnit.NANOSECONDS.toMillis(result.getWaitNanos())); } catch (InterruptedException e) { Thread.currentThread().interrupt(); return ExecutionResult.failure(new FailsafeException(e)); } // Call retry listener if (retryListener != null) retryListener.handle(result, execution); } }; }
/** * Performs post-execution handling of the {@code result}, returning true if complete else false. * * @throws IllegalStateException if the execution is already complete */ synchronized boolean postExecute(ExecutionResult result) { record(result); for (PolicyExecutor<Policy<Object>> policyExecutor : policyExecutors) result = policyExecutor.postExecute(result); waitNanos = result.getWaitNanos(); completed = result.isComplete(); return completed; }
/** * Cancels this and the internal delegate. */ @Override public synchronized boolean cancel(boolean mayInterruptIfRunning) { if (isDone()) return false; boolean cancelResult = super.cancel(mayInterruptIfRunning); if (delegate != null) cancelResult = delegate.cancel(mayInterruptIfRunning); Throwable failure = new CancellationException(); complete(null, failure); executor.handleComplete(ExecutionResult.failure(failure), execution); return cancelResult; }
@SuppressWarnings("unchecked") protected CompletableFuture<ExecutionResult> onFailureAsync(ExecutionResult result, Scheduler scheduler, FailsafeFuture<Object> future) { if (!policy.isAsync()) return CompletableFuture.completedFuture(onFailure(result)); CompletableFuture<ExecutionResult> promise = new CompletableFuture<>(); Callable<Object> callable = () -> promise.complete(onFailure(result)); try { future.inject((Future) scheduler.schedule(callable, result.getWaitNanos(), TimeUnit.NANOSECONDS)); } catch (Exception e) { promise.completeExceptionally(e); } return promise; } }
void handleComplete(ExecutionResult result, ExecutionContext context) { if (successListener != null && result.getSuccessAll()) successListener.handle(result, context.copy()); else if (failureListener != null && !result.getSuccessAll()) failureListener.handle(result, context.copy()); if (completeListener != null) completeListener.handle(result, context.copy()); }
default void handle(ExecutionResult result, ExecutionContext context) { handle(result.getResult(), result.getFailure(), context); } }
static <T> Supplier<CompletableFuture<ExecutionResult>> promiseOf(ContextualSupplier<T> supplier, AbstractExecution execution) { Assert.notNull(supplier, "supplier"); return () -> { ExecutionResult result; try { execution.preExecute(); result = ExecutionResult.success(supplier.get(execution)); } catch (Throwable e) { result = ExecutionResult.failure(e); } execution.record(result); return CompletableFuture.completedFuture(result); }; }
@Override protected ExecutionResult preExecute() { if (policy.allowsExecution()) { policy.preExecute(); return null; } return ExecutionResult.failure(new CircuitBreakerOpenException()); }
/** * Returns whether an execution result can be retried given the configured failure conditions. * * @see #handle(Class...) * @see #handle(List) * @see #handleIf(BiPredicate) * @see #handleIf(Predicate) * @see #handleResult(R) * @see #handleResultIf(Predicate) */ boolean isFailure(ExecutionResult result) { return failureConditions.isEmpty() ? result.getFailure() != null : isFailure((R) result.getResult(), result.getFailure()); }
static <T> Supplier<CompletableFuture<ExecutionResult>> promiseOf(CheckedSupplier<T> supplier, AbstractExecution execution) { Assert.notNull(supplier, "supplier"); return () -> { ExecutionResult result; try { execution.preExecute(); result = ExecutionResult.success(supplier.get()); } catch (Throwable e) { result = ExecutionResult.failure(e); } execution.record(result); return CompletableFuture.completedFuture(result); }; }
/** * Returns a copy of the ExecutionResult with the {@code result} value, and completed and success set to true. */ public ExecutionResult withResult(Object result) { return new ExecutionResult(result, null, nonResult, waitNanos, true, true, successAll); }
static Supplier<CompletableFuture<ExecutionResult>> promiseOf(CheckedRunnable runnable, AbstractExecution execution) { Assert.notNull(runnable, "runnable"); return () -> { ExecutionResult result; try { execution.preExecute(); runnable.run(); result = ExecutionResult.NONE; } catch (Throwable e) { result = ExecutionResult.failure(e); } execution.record(result); return CompletableFuture.completedFuture(result); }; }
private void callFailureListener(ExecutionResult result) { if (result.isComplete() && policy instanceof FailurePolicy) { FailurePolicy failurePolicy = (FailurePolicy) policy; if (failurePolicy.failureListener != null) failurePolicy.failureListener.handle(result, execution); } } }