- 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.getStartTime
now returns aInstant
rather thanDuration
, andExecutionEvent.getStartTime
now returnsOptional<Instant>
.getFailure
,getLastFailure
,recordFailure
and 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
Call
support toFailsafeExecutor
, which can cancel synchrnous calls. - Added
onCancel
callback toExecutionContext
, which can propagate cancellations.
SyncExecutionInternal.isInterruptable()
and.setInterrupted
were removed and.interrupt()
was added instead to simplify performing an interruption.
- Issue #326 - Added support for reserving a
RateLimiter
permit with a wait time.
- Deprecated
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 asgetLastException
,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. - Changed the policy builders to use
CheckedPredicate
andCheckedBiPredicate
instead ofPredicate
andBiPredicate
, allowing exceptions to be thrown which are ignored.
- Issue #309 - Introduced a
Bulkhead
policy. - Issue #318 - Add non-blocking async waiting for rate limiters.
PolicyExecutor.preExecuteAsync
was introduced to support async pre-execution. This is backwards compatible withpreExecute
.
- Issue #308 - Introduced a
RateLimiter
policy.
- 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
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.
- Issue #215 - Added overflow checking for large user-provided
Duration
values.
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.failsafe
package. 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 actualwith
configuration 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()
. RetryPolicy
andCircuitBreaker
can also be constructed with default values usingofDefaults()
.Fallback
andTimeout
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 configuration is now accessible via a
policy.getConfig()
.
- A policy builder can be created via
- In
RetryPolicyBuilder
andCircuitBreakerBuilder
:withDelay
has been renamed towithDelayFn
.withDelayOn
has been renamed towithDelayFnOn
.withDelayWhen
has been renamed towithDelayFnWhen
.- The above method signatures have also been changed to accept a
ContextualSupplier
instead of aDelayFunction
, since it provides access to the same information.
onOpen
,onClose
, andonHalfOpen
methods now accept aCircuitBreakerStateChangedEvent
argument.allowsExecution()
was removed in favor ofacquirePermit()
andtryAcquirePermit()
, which are meant for standalone CircuitBreaker usage.
- The
Fallback
async factory methods have been removed in favor of aFallbackBuilder.withAsync()
option.
Timeout.withInterrupt(boolean)
is nowTimeoutBuilder.withInterrupt()
.
- The standalone
Execution
API, and theAsyncExecution
API created via theFailsafeExecutor.runAsyncExecution
andgetAsyncExecution
methods, have been unified to include:record(R, Throwable)
recordResult(R)
recordException(Throwable)
complete()
- The previously supported
Execution
andAsyncExecution
methods for recording a result have been removed. The methods for performing a retry have also been removed. ForExecution
,isComplete
will indicate whether the execution is complete else if retries can be performed. ForAsyncExecution
retries will automatically be performed, if possible, immediately after a result or failure is recorded. - The
Execution
constructor is no longer visible.Execution
instances 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:
Scheduler
andDefauledScheduledFuture
were moved to thespi
package.Policy
andPolicyExecutor
were moved to thespi
package and some method signatures changed.ExecutionResult
was moved to thespi
package and made generic.- Several new classes were added to the
spi
package to contain internal execution APIs includingExecutionInternal
,SyncExecutionInternal
, andAsyncExecutionInternal
. FailsafeFuture
was 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
compose
method toFailsafeExecutor
. - Issue #293 - Added
RetryPolicyBuilder.withBackoff(Duration, Duration)
and.withDelay(Duration, Duration)
. - Issue #221 -
Executor
instances configured viaFailsafeExecutor.with(Executor)
are now used on all executions, including sync executions, and can be used in conjunction with a separately configuredExecutorService
orScheduler
for async executions. - Added
FailsafeExecutor.getPolicies()
. - Added
isFirstAttempt()
andisRetry()
toExecutionAttempt
, which is available via a few event listeners.
- Fixed #298 -
Fallback.onFailedAttempt
not being called correctly
- Fixed #296 - Add Automatic-Module-Name entry to the generated manifest file
- Added a generic result type
R
toExecutionContext
,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:ContextualSupplier
now 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.getAsyncExecution
to acceptAsyncRunnable
instead ofAsyncSupplier
. This is a breaking change for anygetAsyncExecution
calls, but the fix is to simply remove anyreturn
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 theAsyncExecution
complete
orretry
methods.
- Fixed #289 - Binary imcompatibility with code that was compiled against previous Failsafe versions.
- Added
RetryPolicy.onRetryScheduled
event handler. - Added
ExecutionEvent.getExecutionCount()
andExecutionContext.getExecutionCount()
, which distinguishes between attempts which may have been rejected and completed executions. - Added
Failsafe.none
to create a no-opFailsafeExecutor
. - Improved support for outer Timeouts with retries.
- Fixed #221 - Added support for
FailsafeExecutor.with(Executor)
. - Fixed #277 - Changed
Timeout
to use Failsafe's internal scheduler, so that user providedExecutorService
shutdowns do not interfere with timeouts. - Fixed #266 - Propagate
Future
cancellation to suppliedCompletionStage
when usinggetStageAsync
.
- Fixed #267 - Allow null fallback values to be passed through when using nested fallbacks.
- Fixed #234 - An outer
Timeout
should 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
CircuitBreaker
via:withFailureThreshold(int failureThreshold, Duration failureThresholdingPeriod)
withFailureThreshold(int failureThreshold, int failureExecutionThreshold, Duration failureThresholdingPeriod)
withFailureRateThreshold(int failureRateThreshold, int failureExecutionThreshold, Duration failureThresholdingPeriod)
- Added getters to
CircuitBreaker
for existing count based thresholding settings:getFailureThresholdingCapacity()
getSuccessThresholdingCapacity()
- And added getters to
CircuitBreaker
for 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()
fromRatio
toint
.getFailureThresholdingCapacity
,getFailureRateThreshold
,getFailureExecutionThreshold
, andgetSuccessThresholdingCapacity
provide additional detail about thresholding configuration. - Removed support for the previously deprecated
CircuitBreaker.withTimeout
. TheTimeout
policy 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.apply
was made package private.DelayablePolicy.computeDelay
was 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.DEFAULT
to return the default scheduler Failsafe uses.
- Fixed #206 - Problem with Fallback converting from failure to success.
FailsafeExecutor.get
andFailsafeExecutor.run
will no longer wrapError
instances inFailsafeException
before throwing.
- Fixed potential race between
Timeout
interrupts and execution completion.
- Added a new
Timeout
policy that fails withTimeoutExceededException
. - Added
ExecutionContext.isCancelled()
. - Added
ExecutionContext.getElapsedAttemptTime()
. - Made the internal delay scheduler more adaptive.
- Deprecated
CircuitBreaker.withTimeout
in favor of using a separateTimeout
policy.
- 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.ofException
for returning custom exceptions. - Added
ExecutionContext.getLastResult
and.getLastFailure
to support retries that depend on previous executions - Added
CircuitBreakerOpenException.getCircuitBreaker
RetryPolicy.DelayedFunction
was moved to thenet.jodah.failsafe.function
package.- Removed
RetryPolicy.canApplyDelayFn
- Added support for
Failsafe.with(List<Policy<R>>)
. - Allow
null
Fallback
values.
- A standalone or async execution will only be marked as complete when all policies are complete.
Execution.isComplete
reflects 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
ExecutorService
viaFailsafeExecutor.with(ExecutorService)
. - Added interruptable cancellation for executions ran on
ForkJoinPool
viaCompletableFuture.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
ScheduledExecutorService
orScheduler
be configured. When no scheduler is configured, theForkJoinPool
's common pool will be used by default. Fallback
now support async execution viaofAsync
.CircuitBreaker
supports execution metrics (see below).- Strong typing based on result types is supported throughout the API.
RetryPolicy
now has 3 max attempts by default.CircuitBreaker
now 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
R
that represents the expected result type. - Some of the time related policy configurations have been changed to use
Duration
instead oflong
+TimeUnit
.
- Policy implementations now take a type parameter
- Policy configuration
- Multiple policies can no longer be configured by chaining multiple
Failsafe.with
calls. Instead they must be supplied in a singleFailsafe.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.
- Multiple policies can no longer be configured by chaining multiple
- RetryPoilicy
- The
retryOn
,retryIf
, andretryWhen
methods have been replace withhandleOn
, etc.
- The
- CircuitBreaker
- The
failOn
,failIf
, andfailWhen
methods have been replace withhandleOn
, etc.
- The
- Fallbacks
- Fallbacks must be wrapped in a
Fallback
instance viaFallback.of
- Fallbacks must be wrapped in a
- Failsafe APIs
Supplier
s are now used instead ofCallable
s.java.util.function.Predicate
is used instead of Failsafe's internal Predicate.withFallback
is 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
ExecutionEvent
object, which includes references to the result, failure, and other information. - Event listeners that are specific to policies, such as
onRetry
forRetryPolicy
, must now be configured through the policy instance. The top levelFailsafe
API only supportsonComplete
,onSuccess
, andonFailure
. IndividualPolicy
implementations still supportonSuccess
andonFailure
in addition to policy specific events. - The top level
Failsafe.onSuccess
event listener will only be called if all configured policies consider an execution to be successful, otherwiseonFailure
will be called. - The
Listeners
class 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.Duration
is used instead of Failsafe's ownDuration
impl.ChronoUnit
is used instead ofTimeUnit
in policies.
ExecutionContext.getExecutions
is nowgetAttemptCount
.Schedulers.of(ScheduledExecutorService)
was moved to theScheduler
interface.
CircuitBreaker
preExecute
is 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 -
handleRetriesExceeded
called incorrectly.
- Asynchronous execution attempts no longer throw
CircuitBreakerOpenException
if a configuredCircuitBreaker
is open when an execution is first attempted. Instead, the resultingFuture
is 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.
FailsafeException
now has public constructors, for easier mocking and testing.
- Failsafe will now only throw
FailsafeException
when 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.cancel
calls completion handlers..get
after cancel throwsCancellationException
.
- Fixed #52 - FailsafeFuture.cancel not working as expected.
- Fixed #55 - Fallback always called for asynchronous executions.
CircuitBreakerOpenException
now 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 -
CircuitBreaker
not decrementing currentExections when under load
- Added support for
onRetriesExceeded
listeners. RetryPolicy
can 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
onAbort
listeners. - Added additional async listeners.
RetryPolicy
andCircuitBreaker
now 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
. TheListeners
class is now only meant for Java 6 and 7 usage via method overrides. - Removed listener registration from
Listeners
class. - Removed
AsyncListeners
class. - Removed listener registration from
FailsafeFuture
class.
- 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.concurrent
naming. InvocationStats.getAttemptCount()
was renamed toExecutionStats.getExecutions()
- Added additional contextual callable and runnable support
- Changed to a new API entry point:
Recurrent.with
. - Added
.with
for configuring listeners.
- Added
RetryPolicy.abortOn
,abortWhen
andabortIf
methods to abort retries when matched.
RetryPolicy.retryWhen
was renamed toretryIf
for retrying if aPredicate
is matched.RetryPolicy.retryFor
was renamed toretryWhen
for retrying when a result is matched.Scheduler
andSchedulers
were moved tonet.jodah.recurrent.util.concurrent
.
- Added support for synchronous and asynchronous event listeners
- Added support for
CheckedRunnable
- The
Recurrent.run
methods now require aCheckedRunnable
rather 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.run
andRecurrent.get
methods will throw aRecurrentException
if a failure occurs and the retry policy is exceeded.
- Added better support for invocation tracking
- New Invocation and
AsyncInvocation
APIs
- Add
Scheduler
API - Make
RetryPolicy
copyable
- Require
ContextualCallable
andContextualRunnable
to 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