ExecutionContext.getStartTime now returns a Instant rather than Duration, and ExecutionEvent.getStartTime now returns Optional<Instant>.getFailure, getLastFailure, recordFailure and similar methods for recording Exceptions, which were previously deprecated, were removed. Use getException, getLastException, recordException, etc. instead.Call support to FailsafeExecutor, which can cancel synchrnous calls.onCancel callback to ExecutionContext, which can propagate cancellations.SyncExecutionInternal.isInterruptable() and .setInterrupted were removed and .interrupt() was added instead to simplify performing an interruption.RateLimiter permit with a wait time.ExecutionContext.getLastFailure, Execution.recordFailure and similar methods throughout that API that refer to exceptions as failures. In their place, new methods have been added, such as getLastException, recordException and so on. This clarifies the difference between an exception and a failure, since an exception may or may not be a failure, depending on the policy configuration.CheckedPredicate and CheckedBiPredicate instead of Predicate and BiPredicate, allowing exceptions to be thrown which are ignored.Bulkhead policy.PolicyExecutor.preExecuteAsync was introduced to support async pre-execution. This is backwards compatible with preExecute.RateLimiter policy.with(Executor) not working as expected in some cases..builder(PolicyConfig) methods to each of the policy interfaces, to allow new policies to be built from existing config.RetryPolicyBuilder to allow different types of delays to be configured, replacing previous configuration. Also removed the requirement that a jitter duration be configured after a delay.Duration values.This release introduces some breaking changes to the API:
dev.failsafe. Be sure to update your build config.dev.failsafe package. Be sure to update your imports.builder() and build() methods into the call chain for constructing a policy since the actual with configuration methods are mostly the same as in 2.x policies, with a few changes described below. Some notes:builder(), ex: RetryPolicy.builder().RetryPolicy and CircuitBreaker can also be constructed with default values using ofDefaults().Fallback and Timeout offer additional factory methods for creating a a policy with only their required arguments, without using a builder, ex: Timeout.of(Duration.ofSeconds(10)). Optional arguments must be specified through a builder, ex: Timeout.builder(duration).withInterrupt().build().policy.getConfig().RetryPolicyBuilder and CircuitBreakerBuilder:withDelay has been renamed to withDelayFn.withDelayOn has been renamed to withDelayFnOn.withDelayWhen has been renamed to withDelayFnWhen.ContextualSupplier instead of a DelayFunction, since it provides access to the same information.onOpen, onClose, and onHalfOpen methods now accept a CircuitBreakerStateChangedEvent argument.allowsExecution() was removed in favor of acquirePermit() and tryAcquirePermit(), which are meant for standalone CircuitBreaker usage.Fallback async factory methods have been removed in favor of a FallbackBuilder.withAsync() option.Timeout.withInterrupt(boolean) is now TimeoutBuilder.withInterrupt().Execution API, and the AsyncExecution API created via the FailsafeExecutor.runAsyncExecution and getAsyncExecution methods, have been unified to include:record(R, Throwable)recordResult(R)recordException(Throwable)complete()Execution and AsyncExecution methods for recording a result have been removed. The methods for performing a retry have also been removed. For Execution, isComplete will indicate whether the execution is complete else if retries can be performed. For AsyncExecution retries will automatically be performed, if possible, immediately after a result or failure is recorded.Execution constructor is no longer visible. Execution instances must now be constructed via Execution.of(policies).Execution.getWaitTime() was renamed to getDelay().Failsafe.with(P[] policies) was removed in favor of Failsafe.with(P, P...). This should only affect users who were explicitly passing an array to Failsafe.with.The following changes effect the SPI classes, for users who are extending Failsafe with custom schedulers or policies:
Scheduler and DefauledScheduledFuture were moved to the spi package.Policy and PolicyExecutor were moved to the spi package and some method signatures changed.ExecutionResult was moved to the spi package and made generic.spi package to contain internal execution APIs including ExecutionInternal, SyncExecutionInternal, and AsyncExecutionInternal.FailsafeFuture was moved to the SPI package and some method signatures changed.compose method to FailsafeExecutor.RetryPolicyBuilder.withBackoff(Duration, Duration) and .withDelay(Duration, Duration).Executor instances configured via FailsafeExecutor.with(Executor) are now used on all executions, including sync executions, and can be used in conjunction with a separately configured ExecutorService or Scheduler for async executions.FailsafeExecutor.getPolicies().isFirstAttempt() and isRetry() to ExecutionAttempt, which is available via a few event listeners.Fallback.onFailedAttempt not being called correctlyR to ExecutionContext, Execution, AsyncExecution, and AsyncRunnable. This ensures that result types are unified across the API. It does mean that there are a few minor breaking changes to the API:ContextualSupplier now has an additional result type parameter R. Normally this type is used as lambda parameters where the type is inferred, so most users should not be impacted. But any explicit generic declaration of this type will not compile until the new parameter is added.PolicyExecutor, which is part of the SPI, now accepts an additional result type parameter R. This is only relevant for SPI users who are implementing their own Policies.FailsafeExecutor.getAsyncExecution to accept AsyncRunnable instead of AsyncSupplier. This is a breaking change for any getAsyncExecution calls, but the fix is to simply remove any return statement. The reason for this change is that the provided object does not need to return a result since the result will already be passed asynchronously to one of the AsyncExecution complete or retry methods.RetryPolicy.onRetryScheduled event handler.ExecutionEvent.getExecutionCount() and ExecutionContext.getExecutionCount(), which distinguishes between attempts which may have been rejected and completed executions.Failsafe.none to create a no-op FailsafeExecutor.FailsafeExecutor.with(Executor).Timeout to use Failsafe's internal scheduler, so that user provided ExecutorService shutdowns do not interfere with timeouts.Future cancellation to supplied CompletionStage when using getStageAsync.Timeout should cancel any inner retries.Timeout.withCancel(boolean) and Timeout.canCancel(). Timeouts always cancel any executions and inner retries.Timeout.withInterrupt(boolean) to take the place of withCancel.ExecutionEvent.getElapsedAttemptTime().CircuitBreaker via:withFailureThreshold(int failureThreshold, Duration failureThresholdingPeriod)withFailureThreshold(int failureThreshold, int failureExecutionThreshold, Duration failureThresholdingPeriod)withFailureRateThreshold(int failureRateThreshold, int failureExecutionThreshold, Duration failureThresholdingPeriod)CircuitBreaker for existing count based thresholding settings:getFailureThresholdingCapacity()getSuccessThresholdingCapacity()CircuitBreaker for new time based thresholding settings:getFailureRateThreshold()getFailureExecutionThreshold()getFailureThresholdingPeriod()CircuitBreaker:getSuccessRate()getFailureRate()getExecutionCount()CircuitBreaker's getFailureThreshold() and getSuccessThreshold() from Ratio to int. getFailureThresholdingCapacity, getFailureRateThreshold, getFailureExecutionThreshold, and getSuccessThresholdingCapacity provide additional detail about thresholding configuration.CircuitBreaker.withTimeout. The Timeout policy should be used instead.handleResult(null) always triggering when an exception is thrown.Added support for CompletionStage to the Fallback policy.
Fallback.apply was made package private.DelayablePolicy.computeDelay was made package private.CircuitBreaker.getRemainingDelay().Fallback.VOID.setRemoveOnCancelPolicy(true) for the internal delay scheduler.Scheduler.DEFAULT to return the default scheduler Failsafe uses.FailsafeExecutor.get and FailsafeExecutor.run will no longer wrap Error instances in FailsafeException before throwing.Timeout interrupts and execution completion.Timeout policy that fails with TimeoutExceededException.ExecutionContext.isCancelled().ExecutionContext.getElapsedAttemptTime().CircuitBreaker.withTimeout in favor of using a separate Timeout policy.CompletableFuture.CircuitBreaker.withDelay(DelayFunction)Fallback.ofException for returning custom exceptions.ExecutionContext.getLastResult and .getLastFailure to support retries that depend on previous executionsCircuitBreakerOpenException.getCircuitBreakerRetryPolicy.DelayedFunction was moved to the net.jodah.failsafe.function package.RetryPolicy.canApplyDelayFnFailsafe.with(List<Policy<R>>).null Fallback values.Execution.isComplete reflects this.ExecutorService via FailsafeExecutor.with(ExecutorService).ForkJoinPool via CompletableFuture.cancel(true).getStageAsync.ScheduledExecutorService or Scheduler be configured. When no scheduler is configured, the ForkJoinPool's common pool will be used by default.Fallback now support async execution via ofAsync.CircuitBreaker supports execution metrics (see below).RetryPolicy now has 3 max attempts by default.CircuitBreaker now has a 1 minute delay by default.Failsafe 2.0 includes a few API changes from 1.x that were meant to consolidate behavior such as the execution APIs, which are now based on common Policy implementations, while adding some new features such as Policy composition.
R that represents the expected result type.Duration instead of long + TimeUnit.Failsafe.with calls. Instead they must be supplied in a single Failsafe.with call. This is was intentional to require users to consider the ordering of composed policies. See the README section on policy composition for more details.retryOn, retryIf, and retryWhen methods have been replace with handleOn, etc.failOn, failIf, and failWhen methods have been replace with handleOn, etc.Fallback instance via Fallback.ofSuppliers are now used instead of Callables.java.util.function.Predicate is used instead of Failsafe's internal Predicate.withFallback is no longer supported. Instead, Failsafe.with(fallback...) should be used.getAsync, runAsync, getStageAsync, etc. methods.getAsyncExecution, runAsyncExecution, etc. methods.ExecutionEvent object, which includes references to the result, failure, and other information.onRetry for RetryPolicy, must now be configured through the policy instance. The top level Failsafe API only supports onComplete, onSuccess, and onFailure. Individual Policy implementations still support onSuccess and onFailure in addition to policy specific events.Failsafe.onSuccess event listener will only be called if all configured policies consider an execution to be successful, otherwise onFailure will be called.Listeners class was removed, since it was mostly intended for Java 6/7 users.java.time.Duration is used instead of Failsafe's own Duration impl.ChronoUnit is used instead of TimeUnit in policies.ExecutionContext.getExecutions is now getAttemptCount.Schedulers.of(ScheduledExecutorService) was moved to the Scheduler interface.CircuitBreakerpreExecute is now exposed to support standalone usage.getFailureCount, getFailureRatio, getSuccessCount, and getSuccessRatio.RetryPolicy.withDelay(DelayFunction)RetryPolicy.withDelay(1, 10, TimeUnit.MILLISECONDS)handleRetriesExceeded called incorrectly.CircuitBreakerOpenException if a configured CircuitBreaker is open when an execution is first attempted. Instead, the resulting Future is completed exceptionally with CircuitBreakerOpenException. See issue #84.FailsafeException now has public constructors, for easier mocking and testing.FailsafeException when an execution fails with a checked Exception. See issue #66 for details.FailsafeFutuer.cancel calls completion handlers. .get after cancel throws CancellationException.CircuitBreakerOpenException now extends FailsafeException.CircuitBreaker not decrementing currentExections when under loadonRetriesExceeded listeners.RetryPolicy can be extended (it's no longer marked as final)Failsafe.with(...).onFailure(e -> {}).onAbort listeners.RetryPolicy and CircuitBreaker now support multiple configuration rules. Ex: new RetryPolicy().retryWhen(null).retryWhen(""). If any rule matches then the policy is matched.Failsafe.with(...).onXxx. The Listeners class is now only meant for Java 6 and 7 usage via method overrides.Listeners class.AsyncListeners class.FailsafeFuture class.java.util.concurrent naming.InvocationStats.getAttemptCount() was renamed to ExecutionStats.getExecutions()Recurrent.with..with for configuring listeners.RetryPolicy.abortOn, abortWhen and abortIf methods to abort retries when matched.RetryPolicy.retryWhen was renamed to retryIf for retrying if a Predicate is matched.RetryPolicy.retryFor was renamed to retryWhen for retrying when a result is matched.Scheduler and Schedulers were moved to net.jodah.recurrent.util.concurrent.CheckedRunnableRecurrent.run methods now require a CheckedRunnable rather than Runnable. This allows Recurrent to be used on code that throws checked exceptions without having to wrap the code in try/catch blocks.Recurrent.run and Recurrent.get methods will throw a RecurrentException if a failure occurs and the retry policy is exceeded.AsyncInvocation APIsScheduler APIRetryPolicy copyableContextualCallable and ContextualRunnable to be manually retried