- Issue #365 - Bulkhead policy may drop requests when maxWaitTime is specified.
- Issue #358 - Added full java module descriptors to Failsafe jars.
- Issue #361 - Released execution references inside Failsafe provided CompletableFutures.
ExecutionContext.getStartTimenow returns aInstantrather thanDuration, andExecutionEvent.getStartTimenow returnsOptional<Instant>.getFailure,getLastFailure,recordFailureand similar methods for recording Exceptions, which were previously deprecated, were removed. UsegetException,getLastException,recordException, etc. instead.
- Added additional thread safety checks.
- Fixed an issue where Timeouts would not fire under certain conditions when used outside a RetryPolicy.
- Released OkHttp module.
- Released Retrofit module.
- Added
Callsupport toFailsafeExecutor, which can cancel synchrnous calls. - Added
onCancelcallback toExecutionContext, which can propagate cancellations.
SyncExecutionInternal.isInterruptable()and.setInterruptedwere removed and.interrupt()was added instead to simplify performing an interruption.
- Issue #326 - Added support for reserving a
RateLimiterpermit with a wait time.
- Deprecated
ExecutionContext.getLastFailure,Execution.recordFailureand similar methods throughout that API that refer to exceptions as failures. In their place, new methods have been added, such asgetLastException,recordExceptionand 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. - Changed the policy builders to use
CheckedPredicateandCheckedBiPredicateinstead ofPredicateandBiPredicate, allowing exceptions to be thrown which are ignored.
- Issue #309 - Introduced a
Bulkheadpolicy. - Issue #318 - Add non-blocking async waiting for rate limiters.
PolicyExecutor.preExecuteAsyncwas introduced to support async pre-execution. This is backwards compatible withpreExecute.
- Issue #308 - Introduced a
RateLimiterpolicy.
- Issue #311 -
with(Executor)not working as expected in some cases.
- Issue #310 - Added
.builder(PolicyConfig)methods to each of the policy interfaces, to allow new policies to be built from existing config. - Issue #251 - Relaxed the illegal state validation in
RetryPolicyBuilderto allow different types of delays to be configured, replacing previous configuration. Also removed the requirement that a jitter duration be configured after a delay.
- Issue #215 - Added overflow checking for large user-provided
Durationvalues.
This release introduces some breaking changes to the API:
- The maven group id for Failsafe has changed to
dev.failsafe. Be sure to update your build config. - All files have been moved to the
dev.failsafepackage. Be sure to update your imports.
- All policies now use a builder API. Using the builder API mostly requires inserting
builder()andbuild()methods into the call chain for constructing a policy since the actualwithconfiguration methods are mostly the same as in 2.x policies, with a few changes described below. Some notes:- A policy builder can be created via
builder(), ex:RetryPolicy.builder(). RetryPolicyandCircuitBreakercan also be constructed with default values usingofDefaults().FallbackandTimeoutoffer 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 configuration is now accessible via a
policy.getConfig().
- A policy builder can be created via
- In
RetryPolicyBuilderandCircuitBreakerBuilder:withDelayhas been renamed towithDelayFn.withDelayOnhas been renamed towithDelayFnOn.withDelayWhenhas been renamed towithDelayFnWhen.- The above method signatures have also been changed to accept a
ContextualSupplierinstead of aDelayFunction, since it provides access to the same information.
onOpen,onClose, andonHalfOpenmethods now accept aCircuitBreakerStateChangedEventargument.allowsExecution()was removed in favor ofacquirePermit()andtryAcquirePermit(), which are meant for standalone CircuitBreaker usage.
- The
Fallbackasync factory methods have been removed in favor of aFallbackBuilder.withAsync()option.
Timeout.withInterrupt(boolean)is nowTimeoutBuilder.withInterrupt().
- The standalone
ExecutionAPI, and theAsyncExecutionAPI created via theFailsafeExecutor.runAsyncExecutionandgetAsyncExecutionmethods, have been unified to include:record(R, Throwable)recordResult(R)recordException(Throwable)complete()
- The previously supported
ExecutionandAsyncExecutionmethods for recording a result have been removed. The methods for performing a retry have also been removed. ForExecution,isCompletewill indicate whether the execution is complete else if retries can be performed. ForAsyncExecutionretries will automatically be performed, if possible, immediately after a result or failure is recorded. - The
Executionconstructor is no longer visible.Executioninstances must now be constructed viaExecution.of(policies). Execution.getWaitTime()was renamed togetDelay().
Failsafe.with(P[] policies)was removed in favor ofFailsafe.with(P, P...). This should only affect users who were explicitly passing an array toFailsafe.with.
The following changes effect the SPI classes, for users who are extending Failsafe with custom schedulers or policies:
SchedulerandDefauledScheduledFuturewere moved to thespipackage.PolicyandPolicyExecutorwere moved to thespipackage and some method signatures changed.ExecutionResultwas moved to thespipackage and made generic.- Several new classes were added to the
spipackage to contain internal execution APIs includingExecutionInternal,SyncExecutionInternal, andAsyncExecutionInternal. FailsafeFuturewas moved to the SPI package and some method signatures changed.
- Improved the reliability of async executions, cancellations, and Timeouts.
- Issue #47 - All policies and policy config classes are now threadsafe. Policy builders are not threadsafe.
- Issue #201 - Thread safety is clearly documented in policy, policy config, and policy builder classes.
- Issue #292 - Created an extensible Policy SPI.
- Issue #254 - Added an explicit
composemethod toFailsafeExecutor. - Issue #293 - Added
RetryPolicyBuilder.withBackoff(Duration, Duration)and.withDelay(Duration, Duration). - Issue #221 -
Executorinstances configured viaFailsafeExecutor.with(Executor)are now used on all executions, including sync executions, and can be used in conjunction with a separately configuredExecutorServiceorSchedulerfor async executions. - Added
FailsafeExecutor.getPolicies(). - Added
isFirstAttempt()andisRetry()toExecutionAttempt, which is available via a few event listeners.
- Fixed #298 -
Fallback.onFailedAttemptnot being called correctly
- Fixed #296 - Add Automatic-Module-Name entry to the generated manifest file
- Added a generic result type
RtoExecutionContext,Execution,AsyncExecution, andAsyncRunnable. This ensures that result types are unified across the API. It does mean that there are a few minor breaking changes to the API:ContextualSuppliernow has an additional result type parameterR. 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 parameterR. This is only relevant for SPI users who are implementing their own Policies.
- Changed
FailsafeExecutor.getAsyncExecutionto acceptAsyncRunnableinstead ofAsyncSupplier. This is a breaking change for anygetAsyncExecutioncalls, but the fix is to simply remove anyreturnstatement. 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 theAsyncExecutioncompleteorretrymethods.
- Fixed #289 - Binary imcompatibility with code that was compiled against previous Failsafe versions.
- Added
RetryPolicy.onRetryScheduledevent handler. - Added
ExecutionEvent.getExecutionCount()andExecutionContext.getExecutionCount(), which distinguishes between attempts which may have been rejected and completed executions. - Added
Failsafe.noneto create a no-opFailsafeExecutor. - Improved support for outer Timeouts with retries.
- Fixed #221 - Added support for
FailsafeExecutor.with(Executor). - Fixed #277 - Changed
Timeoutto use Failsafe's internal scheduler, so that user providedExecutorServiceshutdowns do not interfere with timeouts. - Fixed #266 - Propagate
Futurecancellation to suppliedCompletionStagewhen usinggetStageAsync.
- Fixed #267 - Allow null fallback values to be passed through when using nested fallbacks.
- Fixed #234 - An outer
Timeoutshould cancel any inner retries.
- Deprecated
Timeout.withCancel(boolean)andTimeout.canCancel(). Timeouts always cancel any executions and inner retries. - Added
Timeout.withInterrupt(boolean)to take the place ofwithCancel. - Added
ExecutionEvent.getElapsedAttemptTime().
- Added time based thresholding support to
CircuitBreakervia:withFailureThreshold(int failureThreshold, Duration failureThresholdingPeriod)withFailureThreshold(int failureThreshold, int failureExecutionThreshold, Duration failureThresholdingPeriod)withFailureRateThreshold(int failureRateThreshold, int failureExecutionThreshold, Duration failureThresholdingPeriod)
- Added getters to
CircuitBreakerfor existing count based thresholding settings:getFailureThresholdingCapacity()getSuccessThresholdingCapacity()
- And added getters to
CircuitBreakerfor new time based thresholding settings:getFailureRateThreshold()getFailureExecutionThreshold()getFailureThresholdingPeriod()
- Added some new metrics to
CircuitBreaker:getSuccessRate()getFailureRate()getExecutionCount()
- Changed the return type of
CircuitBreaker'sgetFailureThreshold()andgetSuccessThreshold()fromRatiotoint.getFailureThresholdingCapacity,getFailureRateThreshold,getFailureExecutionThreshold, andgetSuccessThresholdingCapacityprovide additional detail about thresholding configuration. - Removed support for the previously deprecated
CircuitBreaker.withTimeout. TheTimeoutpolicy should be used instead.
- Fixed #242 - Delays not occurring between manually triggered async execution retries.
- Re-worked internal threading to only create async threads immediately prior to supplier execution. See #230.
- Fixed #240 -
handleResult(null)always triggering when an exception is thrown.
Added support for CompletionStage to the Fallback policy.
- Fixed #224 - Allow combining random delay and jitter.
Fallback.applywas made package private.DelayablePolicy.computeDelaywas made package private.
- Added
CircuitBreaker.getRemainingDelay(). - Added support for
Fallback.VOID.
- Fixed #216 - Incorrect computation of randomDelay.
- Set
setRemoveOnCancelPolicy(true)for the internal delay scheduler. - Added
Scheduler.DEFAULTto return the default scheduler Failsafe uses.
- Fixed #206 - Problem with Fallback converting from failure to success.
FailsafeExecutor.getandFailsafeExecutor.runwill no longer wrapErrorinstances inFailsafeExceptionbefore throwing.
- Fixed potential race between
Timeoutinterrupts and execution completion.
- Added a new
Timeoutpolicy that fails withTimeoutExceededException. - Added
ExecutionContext.isCancelled(). - Added
ExecutionContext.getElapsedAttemptTime(). - Made the internal delay scheduler more adaptive.
- Deprecated
CircuitBreaker.withTimeoutin favor of using a separateTimeoutpolicy.
- Reset interrupt flag when a synchronous execution is interrupted.
- Improved handling around externally completing a Failsafe
CompletableFuture.
- Added support for
CircuitBreaker.withDelay(DelayFunction) - Added
Fallback.ofExceptionfor returning custom exceptions. - Added
ExecutionContext.getLastResultand.getLastFailureto support retries that depend on previous executions - Added
CircuitBreakerOpenException.getCircuitBreaker
RetryPolicy.DelayedFunctionwas moved to thenet.jodah.failsafe.functionpackage.- Removed
RetryPolicy.canApplyDelayFn
- Added support for
Failsafe.with(List<Policy<R>>). - Allow
nullFallbackvalues.
- A standalone or async execution will only be marked as complete when all policies are complete.
Execution.isCompletereflects this.
- Issue #190 - Failure listener called on success for async executions.
- Issue #191 - Add missing listeners to RetryPolicy copy constructor.
- Issue #192 - Problem with detecting completion when performing async execution.
- Added support for using
ExecutorServiceviaFailsafeExecutor.with(ExecutorService). - Added interruptable cancellation for executions ran on
ForkJoinPoolviaCompletableFuture.cancel(true).
- Issue #171 - Handle completed futures when using
getStageAsync.
- Policy composition is now supported.
- A Policy SPI is now available.
- Async execution is now supported without requiring that a
ScheduledExecutorServiceorSchedulerbe configured. When no scheduler is configured, theForkJoinPool's common pool will be used by default. Fallbacknow support async execution viaofAsync.CircuitBreakersupports execution metrics (see below).- Strong typing based on result types is supported throughout the API.
RetryPolicynow has 3 max attempts by default.CircuitBreakernow has a 1 minute delay by default.
- Java 8+ is now required
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.
- Policies
- Policy implementations now take a type parameter
Rthat represents the expected result type. - Some of the time related policy configurations have been changed to use
Durationinstead oflong+TimeUnit.
- Policy implementations now take a type parameter
- Policy configuration
- Multiple policies can no longer be configured by chaining multiple
Failsafe.withcalls. Instead they must be supplied in a singleFailsafe.withcall. This is was intentional to require users to consider the ordering of composed policies. See the README section on policy composition for more details.
- Multiple policies can no longer be configured by chaining multiple
- RetryPoilicy
- The
retryOn,retryIf, andretryWhenmethods have been replace withhandleOn, etc.
- The
- CircuitBreaker
- The
failOn,failIf, andfailWhenmethods have been replace withhandleOn, etc.
- The
- Fallbacks
- Fallbacks must be wrapped in a
Fallbackinstance viaFallback.of
- Fallbacks must be wrapped in a
- Failsafe APIs
Suppliers are now used instead ofCallables.java.util.function.Predicateis used instead of Failsafe's internal Predicate.withFallbackis no longer supported. Instead,Failsafe.with(fallback...)should be used.
- Async execution
- Async execution is now performed with the
getAsync,runAsync,getStageAsync, etc. methods. - Async API integration is now supported via the
getAsyncExecution,runAsyncExecution, etc. methods.
- Async execution is now performed with the
- Event listeners
- Event listeners now all consume a single
ExecutionEventobject, which includes references to the result, failure, and other information. - Event listeners that are specific to policies, such as
onRetryforRetryPolicy, must now be configured through the policy instance. The top levelFailsafeAPI only supportsonComplete,onSuccess, andonFailure. IndividualPolicyimplementations still supportonSuccessandonFailurein addition to policy specific events. - The top level
Failsafe.onSuccessevent listener will only be called if all configured policies consider an execution to be successful, otherwiseonFailurewill be called. - The
Listenersclass was removed, since it was mostly intended for Java 6/7 users. - The async event listener APIs were removed. Events will always be delivered in the same thread as the execution that they follow or preceed, including for async executions.
- Event listeners now all consume a single
- Java 8
java.time.Durationis used instead of Failsafe's ownDurationimpl.ChronoUnitis used instead ofTimeUnitin policies.
ExecutionContext.getExecutionsis nowgetAttemptCount.Schedulers.of(ScheduledExecutorService)was moved to theSchedulerinterface.
CircuitBreakerpreExecuteis now exposed to support standalone usage.- Execution metrics are available via
getFailureCount,getFailureRatio,getSuccessCount, andgetSuccessRatio.
- Issue #152 - Min/max delay was not being computed correctly
- Issue #115 - Jitter bigger than Delay causes a (random) failure at runtime
- Issue #116 - Setting jitter without a delay works fine bug
- Issue #123 - Ability to reset the jitterFactor
- Issue #110 - Added support for computed delays:
RetryPolicy.withDelay(DelayFunction) - Issue #126 - Added support for random delays:
RetryPolicy.withDelay(1, 10, TimeUnit.MILLISECONDS)
- Issue #97 - Should not increment exponential backoff time on first attempt
- Issue #92 -
handleRetriesExceededcalled incorrectly.
- Asynchronous execution attempts no longer throw
CircuitBreakerOpenExceptionif a configuredCircuitBreakeris open when an execution is first attempted. Instead, the resultingFutureis completed exceptionally withCircuitBreakerOpenException. See issue #84.
- Issue #81 - Added single argument failure configuration to avoid varargs related warnings.
- Fixed #76 - Make sure AsyncExecution.completeOrRetry is called when Error is thrown.
- Fixed #75 - Incorrect future completion when a fallback is present.
FailsafeExceptionnow has public constructors, for easier mocking and testing.
- Failsafe will now only throw
FailsafeExceptionwhen an execution fails with a checkedException. See issue #66 for details.
- Fixed #59 - Classloading issue on Java 6/7.
- Fixed #63 - Proper handling of thread interrupts during synchronous execution delays.
- Fixed #54 - Added hashCode and equals implementations to Duration.
- Added OSGi support.
FailsafeFutuer.cancelcalls completion handlers..getafter cancel throwsCancellationException.
- Fixed #52 - FailsafeFuture.cancel not working as expected.
- Fixed #55 - Fallback always called for asynchronous executions.
CircuitBreakerOpenExceptionnow extendsFailsafeException.
- Various fallback and listener API additions and improvements
- Added support for retry delay jitter.
- Added support for fallbacks.
- Fixed issue #36 - Failed attempt listener not always called on completion.
- Fixed issue #34 - CircuitBreaker should default to closed state.
- Fixed #33 -
CircuitBreakernot decrementing currentExections when under load
- Added support for
onRetriesExceededlisteners. RetryPolicycan be extended (it's no longer marked as final)
- Abort should not call failure listeners.
- Simplified listeners API.
- Added support for failure listeners via
Failsafe.with(...).onFailure(e -> {}). - Added
onAbortlisteners. - Added additional async listeners.
RetryPolicyandCircuitBreakernow support multiple configuration rules. Ex:new RetryPolicy().retryWhen(null).retryWhen(""). If any rule matches then the policy is matched.
- Added top level support for listener registration via
Failsafe.with(...).onXxx. TheListenersclass is now only meant for Java 6 and 7 usage via method overrides. - Removed listener registration from
Listenersclass. - Removed
AsyncListenersclass. - Removed listener registration from
FailsafeFutureclass.
- Added support for circuit breakers
- Project renamed from Recurrent to Failsafe
- Added better support for scheduling failure handling
- Fixed RetryPolicy failure assignability checking
- Invocation APIs were renamed to Execution to better align with the
java.util.concurrentnaming. InvocationStats.getAttemptCount()was renamed toExecutionStats.getExecutions()
- Added additional contextual callable and runnable support
- Changed to a new API entry point:
Recurrent.with. - Added
.withfor configuring listeners.
- Added
RetryPolicy.abortOn,abortWhenandabortIfmethods to abort retries when matched.
RetryPolicy.retryWhenwas renamed toretryIffor retrying if aPredicateis matched.RetryPolicy.retryForwas renamed toretryWhenfor retrying when a result is matched.SchedulerandSchedulerswere moved tonet.jodah.recurrent.util.concurrent.
- Added support for synchronous and asynchronous event listeners
- Added support for
CheckedRunnable
- The
Recurrent.runmethods now require aCheckedRunnablerather thanRunnable. This allows Recurrent to be used on code that throws checked exceptions without having to wrap the code in try/catch blocks. - The synchronous
Recurrent.runandRecurrent.getmethods will throw aRecurrentExceptionif a failure occurs and the retry policy is exceeded.
- Added better support for invocation tracking
- New Invocation and
AsyncInvocationAPIs
- Add
SchedulerAPI - Make
RetryPolicycopyable
- Require
ContextualCallableandContextualRunnableto be manually retried - Add support for checking multiple retry policy conditions
- Make ContextualRunnable throw Exception
- Add support for retrying when an invocation result matches a policy
- Added support for seprate retry tracking.
- Initial Release