pax_global_header 0000666 0000000 0000000 00000000064 14445610507 0014520 g ustar 00root root 0000000 0000000 52 comment=8ae344fda21eb00c32a34bbd9517babe5b6fadc5
failsafe-failsafe-parent-3.3.2/ 0000775 0000000 0000000 00000000000 14445610507 0016336 5 ustar 00root root 0000000 0000000 failsafe-failsafe-parent-3.3.2/.github/ 0000775 0000000 0000000 00000000000 14445610507 0017676 5 ustar 00root root 0000000 0000000 failsafe-failsafe-parent-3.3.2/.github/workflows/ 0000775 0000000 0000000 00000000000 14445610507 0021733 5 ustar 00root root 0000000 0000000 failsafe-failsafe-parent-3.3.2/.github/workflows/maven.yml 0000664 0000000 0000000 00000001366 14445610507 0023572 0 ustar 00root root 0000000 0000000 # This workflow will build a Java project with Maven
# For more information see: https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-maven
name: build
on: [push, pull_request]
jobs:
compile:
runs-on: ubuntu-latest
strategy:
matrix:
java: [ 8, 11, 17 ]
jdk: ['temurin', 'zulu']
name: Java ${{ matrix.java }} ${{ matrix.jdk }}
steps:
- name: Checkout Source Code
uses: actions/checkout@v2
- name: Setup Java
uses: actions/setup-java@v2
with:
distribution: ${{ matrix.jdk }}
java-package: jdk
java-version: ${{ matrix.java }}
cache: 'maven'
- name: Build with maven
run: mvn -B test
failsafe-failsafe-parent-3.3.2/.gitignore 0000664 0000000 0000000 00000000134 14445610507 0020324 0 ustar 00root root 0000000 0000000 target/
*~
.project
.classpath
.settings/
test-output/
docs/
.idea
*.iml
_site
.java-version failsafe-failsafe-parent-3.3.2/CHANGELOG.md 0000664 0000000 0000000 00000060602 14445610507 0020153 0 ustar 00root root 0000000 0000000 # 3.3.2
### Bug Fixes
- Issue #365 - Bulkhead policy may drop requests when maxWaitTime is specified.
# 3.3.1
### Improevments
- Issue #358 - Added full java module descriptors to Failsafe jars.
- Issue #361 - Released execution references inside Failsafe provided CompletableFutures.
# 3.3.0
### API Changes
- `ExecutionContext.getStartTime` now returns a `Instant` rather than `Duration`, and `ExecutionEvent.getStartTime` now returns `Optional`.
- `getFailure`, `getLastFailure`, `recordFailure` and similar methods for recording Exceptions, which were previously deprecated, were removed. Use `getException`, `getLastException`, `recordException`, etc. instead.
# 3.2.4
### Improvements
- Added additional thread safety checks.
# 3.2.3
### Bug Fixes
- Fixed an issue where Timeouts would not fire under certain conditions when used outside a RetryPolicy.
# 3.2.2
### Improvements
- Released [OkHttp](https://square.github.io/okhttp/) module.
- Released [Retrofit](https://square.github.io/retrofit/) module.
- Added `Call` support to `FailsafeExecutor`, which can cancel synchrnous calls.
- Added `onCancel` callback to `ExecutionContext`, which can propagate cancellations.
### SPI Changes
- `SyncExecutionInternal.isInterruptable()` and `.setInterrupted` were removed and `.interrupt()` was added instead to simplify performing an interruption.
# 3.2.1
### Improvements
- Issue #326 - Added support for reserving a `RateLimiter` permit with a wait time.
### API Changes
- 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 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.
- Changed the policy builders to use `CheckedPredicate` and `CheckedBiPredicate` instead of `Predicate` and `BiPredicate`, allowing exceptions to be thrown which are ignored.
# 3.2.0
### Improvements
- Issue #309 - Introduced a `Bulkhead` policy.
- Issue #318 - Add non-blocking async waiting for rate limiters.
### SPI Changes
- `PolicyExecutor.preExecuteAsync` was introduced to support async pre-execution. This is backwards compatible with `preExecute`.
# 3.1.0
### Improvements
- Issue #308 - Introduced a `RateLimiter` policy.
# 3.0.2
### Bug Fixes
- Issue #311 - `with(Executor)` not working as expected in some cases.
# 3.0.1
### Improvements
- 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.
### Bug Fixes
- Issue #215 - Added overflow checking for large user-provided `Duration` values.
# 3.0
### API Changes
This release introduces some breaking changes to the API:
#### General
- 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.
#### Policies
- All policies now use a builder API. Using the builder API mostly requires inserting `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:
- A policy builder can be created via `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 configuration is now accessible via a `policy.getConfig()`.
#### RetryPolicy and CircuitBreaker
- In `RetryPolicyBuilder` and `CircuitBreakerBuilder`:
- `withDelay` has been renamed to `withDelayFn`.
- `withDelayOn` has been renamed to `withDelayFnOn`.
- `withDelayWhen` has been renamed to `withDelayFnWhen`.
- The above method signatures have also been changed to accept a `ContextualSupplier` instead of a `DelayFunction`, since it provides access to the same information.
#### CircuitBreaker
- `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
- The `Fallback` async factory methods have been removed in favor of a `FallbackBuilder.withAsync()` option.
#### Timeout
- `Timeout.withInterrupt(boolean)` is now `TimeoutBuilder.withInterrupt()`.
#### Execution and AsyncExecution
- The standalone `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()`
- The previously supported `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.
- The `Execution` constructor is no longer visible. `Execution` instances must now be constructed via `Execution.of(policies)`.
- `Execution.getWaitTime()` was renamed to `getDelay()`.
#### Failsafe class
- `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`.
### SPI Changes
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.
- Several new classes were added to the `spi` package to contain internal execution APIs including `ExecutionInternal`, `SyncExecutionInternal`, and `AsyncExecutionInternal`.
- `FailsafeFuture` was moved to the SPI package and some method signatures changed.
### Bug Fixes
- Improved the reliability of async executions, cancellations, and Timeouts.
### Improvements
- 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 to `FailsafeExecutor`.
- Issue #293 - Added `RetryPolicyBuilder.withBackoff(Duration, Duration)` and `.withDelay(Duration, Duration)`.
- Issue #221 - `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.
- Added `FailsafeExecutor.getPolicies()`.
- Added `isFirstAttempt()` and `isRetry()` to `ExecutionAttempt`, which is available via a few event listeners.
# 2.4.4
### Bug Fixes
- Fixed #298 - `Fallback.onFailedAttempt` not being called correctly
### Improvements
- Fixed #296 - Add Automatic-Module-Name entry to the generated manifest file
### API Changes
- Added a generic result type `R` 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.
- Changed `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.
# 2.4.3
### Bug Fixes
- Fixed #289 - Binary imcompatibility with code that was compiled against previous Failsafe versions.
# 2.4.2
### Improvements
- Added `RetryPolicy.onRetryScheduled` event handler.
- Added `ExecutionEvent.getExecutionCount()` and `ExecutionContext.getExecutionCount()`, which distinguishes between attempts which may have been rejected and completed executions.
- Added `Failsafe.none` to create a no-op `FailsafeExecutor`.
- 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 provided `ExecutorService` shutdowns do not interfere with timeouts.
- Fixed #266 - Propagate `Future` cancellation to supplied `CompletionStage` when using `getStageAsync`.
### Bug Fixes
- Fixed #267 - Allow null fallback values to be passed through when using nested fallbacks.
# 2.4.1
### Improvements
- Fixed #234 - An outer `Timeout` should cancel any inner retries.
### API Changes
- Deprecated `Timeout.withCancel(boolean)` and `Timeout.canCancel()`. Timeouts always cancel any executions and inner retries.
- Added `Timeout.withInterrupt(boolean)` to take the place of `withCancel`.
- Added `ExecutionEvent.getElapsedAttemptTime()`.
# 2.4.0
### Improvements
- 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()`
### API Changes
- Changed the return type of `CircuitBreaker`'s `getFailureThreshold()` and `getSuccessThreshold()` from `Ratio` to `int`. `getFailureThresholdingCapacity`, `getFailureRateThreshold`, `getFailureExecutionThreshold`, and `getSuccessThresholdingCapacity` provide additional detail about thresholding configuration.
- Removed support for the previously deprecated `CircuitBreaker.withTimeout`. The `Timeout` policy should be used instead.
# 2.3.5
### Bug Fixes
- Fixed #242 - Delays not occurring between manually triggered async execution retries.
# 2.3.4
### Improvements
- Re-worked internal threading to only create async threads immediately prior to supplier execution. See #230.
### Bug Fixes
- Fixed #240 - `handleResult(null)` always triggering when an exception is thrown.
# 2.3.3
### Improvements
Added support for `CompletionStage` to the `Fallback` policy.
### Bug Fixes
- Fixed #224 - Allow combining random delay and jitter.
### API Changes
- `Fallback.apply` was made package private.
- `DelayablePolicy.computeDelay` was made package private.
# 2.3.2
### Improvements
- Added `CircuitBreaker.getRemainingDelay()`.
- Added support for `Fallback.VOID`.
### Bug Fixes
- Fixed #216 - Incorrect computation of randomDelay.
# 2.3.1
### Improvements
- Set `setRemoveOnCancelPolicy(true)` for the internal delay scheduler.
- Added `Scheduler.DEFAULT` to return the default scheduler Failsafe uses.
### Bug Fixes
- Fixed #206 - Problem with Fallback converting from failure to success.
# 2.3.0
### Behavior Changes
- `FailsafeExecutor.get` and `FailsafeExecutor.run` will no longer wrap `Error` instances in `FailsafeException` before throwing.
### Bug Fixes
- Fixed potential race between `Timeout` interrupts and execution completion.
# 2.2.0
### Improvements
- Added a new `Timeout` policy that fails with `TimeoutExceededException`.
- Added `ExecutionContext.isCancelled()`.
- Added `ExecutionContext.getElapsedAttemptTime()`.
- Made the internal delay scheduler more adaptive.
### API Changes
- Deprecated `CircuitBreaker.withTimeout` in favor of using a separate `Timeout` policy.
### Bug Fixes
- Reset interrupt flag when a synchronous execution is interrupted.
- Improved handling around externally completing a Failsafe `CompletableFuture`.
# 2.1.1
### Improvements
- 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`
### API Changes
- `RetryPolicy.DelayedFunction` was moved to the `net.jodah.failsafe.function` package.
- Removed `RetryPolicy.canApplyDelayFn`
# 2.1.0
### Improvements
- Added support for `Failsafe.with(List>)`.
- Allow `null` `Fallback` values.
### Behavior Changes
- A [standalone](https://github.com/jhalterman/failsafe#execution-tracking) or [async execution](https://github.com/jhalterman/failsafe#asynchronous-api-integration) will only be marked as complete when all policies are complete. `Execution.isComplete` reflects this.
### Bug Fixes
- 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.
# 2.0.1
### Improvements
- Added support for using `ExecutorService` via `FailsafeExecutor.with(ExecutorService)`.
- Added interruptable cancellation for executions ran on `ForkJoinPool` via `CompletableFuture.cancel(true)`.
### Bug Fixes
- Issue #171 - Handle completed futures when using `getStageAsync`.
# 2.0
### Improvements
* [Policy composition](README.md#policy-composition) is now supported.
* [A Policy SPI](README.md#policy-spi) is now available.
* Async execution is now supported without requiring that a `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).
* Strong typing based on result types is supported throughout the API.
### Behavior Changes
- `RetryPolicy` now has 3 max attempts by default.
- `CircuitBreaker` now has a 1 minute delay by default.
### JRE Changes
- Java 8+ is now required
### API Changes
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 of `long` + `TimeUnit`.
- Policy configuration
- Multiple policies can no longer be configured by chaining multiple `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](README.md#policy-composition) for more details.
- RetryPoilicy
- The `retryOn`, `retryIf`, and `retryWhen` methods have been replace with `handleOn`, etc.
- CircuitBreaker
- The `failOn`, `failIf`, and `failWhen` methods have been replace with `handleOn`, etc.
- Fallbacks
- Fallbacks must be wrapped in a `Fallback` instance via `Fallback.of`
- Failsafe APIs
- `Supplier`s are now used instead of `Callable`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.
- 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` 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.
- The top level `Failsafe.onSuccess` event listener will only be called if *all* configured policies consider an execution to be successful, otherwise `onFailure` 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.
- Java 8
- `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.
### API Additions
- `CircuitBreaker`
- `preExecute` is now exposed to support standalone usage.
- Execution metrics are available via `getFailureCount`, `getFailureRatio`, `getSuccessCount`, and `getSuccessRatio`.
### Bug Fixes
* Issue #152 - Min/max delay was not being computed correctly
# 1.1.0
### Bug Fixes
* 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
### Improvements
* Issue #110 - Added support for computed delays: `RetryPolicy.withDelay(DelayFunction)`
* Issue #126 - Added support for random delays: `RetryPolicy.withDelay(1, 10, TimeUnit.MILLISECONDS)`
# 1.0.5
### Bug Fixes
* Issue #97 - Should not increment exponential backoff time on first attempt
* Issue #92 - `handleRetriesExceeded` called incorrectly.
# 1.0.4
### API Changes
* Asynchronous execution attempts no longer throw `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](https://github.com/jhalterman/failsafe/issues/84).
### Improvements
* Issue #81 - Added single argument failure configuration to avoid varargs related warnings.
# 1.0.3
### Bug Fixes
* Fixed #76 - Make sure AsyncExecution.completeOrRetry is called when Error is thrown.
# 1.0.2
### Bug Fixes
* Fixed #75 - Incorrect future completion when a fallback is present.
# 1.0.1
### Changes
* `FailsafeException` now has public constructors, for easier mocking and testing.
# 1.0.0
### API Changes
* Failsafe will now only throw `FailsafeException` when an execution fails with a checked `Exception`. See [issue #66](https://github.com/jhalterman/failsafe/issues/66) for details.
# 0.9.5
### Bug Fixes
* Fixed #59 - Classloading issue on Java 6/7.
# 0.9.4
### Bug Fixes
* Fixed #63 - Proper handling of thread interrupts during synchronous execution delays.
* Fixed #54 - Added hashCode and equals implementations to Duration.
# 0.9.3
### New Features
* Added OSGi support.
* `FailsafeFutuer.cancel` calls completion handlers. `.get` after cancel throws `CancellationException`.
### Bug Fixes
* Fixed #52 - FailsafeFuture.cancel not working as expected.
* Fixed #55 - Fallback always called for asynchronous executions.
### API Changes
* `CircuitBreakerOpenException` now extends `FailsafeException`.
# 0.9.2
### New Features
* Various fallback and listener API additions and improvements
# 0.9.1
### New Features
* Added support for retry delay [jitter](https://github.com/jhalterman/failsafe#retry-policies).
# 0.9.0
### New Features
* Added support for [fallbacks](https://github.com/jhalterman/failsafe#fallbacks).
### Bug Fixes
* Fixed issue #36 - Failed attempt listener not always called on completion.
* Fixed issue #34 - CircuitBreaker should default to closed state.
# 0.8.3
### Bug Fixes
* Fixed #33 - `CircuitBreaker` not decrementing currentExections when under load
# 0.8.2
### New Features
* Added support for `onRetriesExceeded` listeners.
* `RetryPolicy` can be extended (it's no longer marked as final)
### Bug Fixes
* Abort should not call failure listeners.
# 0.8.1
### New Features
* Simplified listeners API.
* Added support for failure listeners via `Failsafe.with(...).onFailure(e -> {})`.
* Added `onAbort` listeners.
* Added additional async listeners.
* `RetryPolicy` and `CircuitBreaker` now support multiple configuration rules. Ex: `new RetryPolicy().retryWhen(null).retryWhen("")`. If any rule matches then the policy is matched.
### API Changes
* Added top level support for listener registration via `Failsafe.with(...).onXxx`. The `Listeners` 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.
# 0.8.0
### New Features
* Added support for circuit breakers
### API Changes
* Project renamed from Recurrent to Failsafe
# 0.7.1
### Bug Fixes
* Added better support for scheduling failure handling
* Fixed RetryPolicy failure assignability checking
### API Changes
* Invocation APIs were renamed to Execution to better align with the `java.util.concurrent` naming.
* `InvocationStats.getAttemptCount()` was renamed to `ExecutionStats.getExecutions()`
# 0.7.0
### New Features
* Added additional contextual callable and runnable support
### API Changes
* Changed to a new API entry point: `Recurrent.with`.
* Added `.with` for configuring listeners.
# 0.6.0
### New Features
* Added `RetryPolicy.abortOn`, `abortWhen` and `abortIf` methods to abort retries when matched.
### API Changes
* `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`.
# 0.5.0
### New Features
* Added support for synchronous and asynchronous event listeners
* Added support for `CheckedRunnable`
### API Changes
* The `Recurrent.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.
* The synchronous `Recurrent.run` and `Recurrent.get` methods will throw a `RecurrentException` if a failure occurs and the retry policy is exceeded.
# 0.4.0
### New Features
* Added better support for invocation tracking
### API Changes
* New Invocation and `AsyncInvocation` APIs
# 0.3.3
### New Features
* Add `Scheduler` API
* Make `RetryPolicy` copyable
### Behavior Changes
* Require `ContextualCallable` and `ContextualRunnable` to be manually retried
* Add support for checking multiple retry policy conditions
### API Changes
* Make ContextualRunnable throw Exception
# 0.3.2
### New Features
* Add support for retrying when an invocation result matches a policy
# 0.3.1
### New Features
* Added support for seprate retry tracking.
# 0.3.0
* Initial Release failsafe-failsafe-parent-3.3.2/CONTRIBUTING.md 0000664 0000000 0000000 00000002717 14445610507 0020576 0 ustar 00root root 0000000 0000000 ### Reporting Bugs
Bug reports are welcome and appreciated. When filing an issue, please include a small code snippet that demonstrates the bug if you can, else include a good description of how to reproduce the bug.
### Contributing Bug Fixes
Pull requests for bugs related to existing features are always welcome.
### Requesting Features
Feature requests are welcome by filing an issue. In general we try to make sure that new features fit well with the existing ones and that they're broadly useful. If your feature will require new APIs or API changes, feel free to share an example of how you think the API should look.
### Contributing Features
If you have an idea for a new feature, the best place to start is not with a pull request but rather by opening an issue describing how the feature or API change should work and why you think it is necessary. The reason we suggest starting with an issue rather than a pull request is that we like to make sure every feature and API change is widely useful and a good fit for the library, and would hate to reject a PR that someone puts a lot of time into if it's not a good fit.
If your feature idea sounds good, you can then submit a PR, else we'll schedule the feature for implementation.
### Contributing Documentation or Website Fixes
Fixes to the Failsafe documentation or website are welcome. Just clone the [website repo](https://github.com/failsafe-lib/failsafe-lib.github.io) and feel free to submit a pull request.
failsafe-failsafe-parent-3.3.2/LICENSE 0000664 0000000 0000000 00000023675 14445610507 0017360 0 ustar 00root root 0000000 0000000
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS failsafe-failsafe-parent-3.3.2/README.md 0000664 0000000 0000000 00000003460 14445610507 0017620 0 ustar 00root root 0000000 0000000 # Failsafe
[](https://github.com/failsafe-lib/failsafe/actions)
[](https://maven-badges.herokuapp.com/maven-central/dev.failsafe/failsafe)
[](http://www.apache.org/licenses/LICENSE-2.0.html)
[](https://failsafe.dev/javadoc/core)
[](https://gitter.im/jhalterman/failsafe)
Failsafe is a lightweight, zero-dependency library for handling failures in Java 8+, with a concise API for handling everyday use cases and the flexibility to handle everything else. It works by wrapping executable logic with one or more resilience policies, which can be combined and composed as needed.
Policies include [Retry](https://failsafe.dev/retry/), [CircuitBreaker](https://failsafe.dev/circuit-breaker/), [RateLimiter](https://failsafe.dev/rate-limiter/), [Timeout](https://failsafe.dev/timeout/), [Bulkhead](https://failsafe.dev/bulkhead/), and [Fallback](https://failsafe.dev/fallback/). Additional modules include [OkHttp](https://failsafe.dev/okhttp/) and [Retrofit](https://failsafe.dev/retrofit/).
## Usage
Visit [failsafe.dev](https://failsafe.dev) for usage info, docs, and additional resources.
## Contributing
Check out the [contributing guidelines](https://github.com/failsafe-lib/failsafe/blob/master/CONTRIBUTING.md).
## License
Copyright Jonathan Halterman and friends. Released under the [Apache 2.0 license](https://github.com/failsafe-lib/failsafe/blob/master/LICENSE). failsafe-failsafe-parent-3.3.2/VERSIONING.md 0000664 0000000 0000000 00000000703 14445610507 0020343 0 ustar 00root root 0000000 0000000 ### Versioning
Failsafe follows MAJOR.MINOR.PATCH versioning where:
- MAJOR versions contain significant new features and potentially significant incompatible API changes.
- MINOR versions contain new features and potentially minor yet incompatible API changes.
- PATCH versions contain bug fixes and minor new features that are fully backwards compatible.
All versions, new features, and API changes are described in the [CHANGELOG](CHANGELOG.md). failsafe-failsafe-parent-3.3.2/bin/ 0000775 0000000 0000000 00000000000 14445610507 0017106 5 ustar 00root root 0000000 0000000 failsafe-failsafe-parent-3.3.2/bin/push-javadoc.sh 0000775 0000000 0000000 00000003176 14445610507 0022040 0 ustar 00root root 0000000 0000000 #!/bin/sh
# run from top level dir
ORG=failsafe-lib
REPO=failsafe.dev
pwd=`pwd`
build () {
echo "Building Javadocs for $1"
cd $pwd
if [ "$1" != "core" ]; then
cd modules
fi
cd $1
mvn javadoc:javadoc -Djv=$apiVersion
rm -rf target/docs
git clone git@github.com:$ORG/$REPO.git target/docs
cd target/docs
git rm -rf javadoc/$1
mkdir -p javadoc/$1
mv -v ../site/apidocs/* javadoc/$1
patchFavIcon "javadoc" "../assets/images/favicon.png"
commit && echo "Published Javadocs for $1"
}
patchFavIcon () {
echo "Patching favicons"
for f in $1/*.html ; do
if [ -f "$f" ]; then # if no .html files exist, f is literal "*.html"
tmpfile=`mktemp patch_favicon_XXXXX`
# This creates tmpfile, with the same permissions as $f.
# The next command will overwrite it but preserve the permissions.
# Hat tip to http://superuser.com/questions/170226/standard-way-to-duplicate-a-files-permissions for this trick.
\cp -p $f $tmpfile
sed -e " s%\$%%" $f > $tmpfile
DIFF=$(diff $f $tmpfile)
if [ "$DIFF" != "" ]
then
echo "$f modified with favicon"
fi
mv -f $tmpfile $f
fi;
done ;
for d in $1/* ; do
if [ -d $d ]; then echo "descending to "$d ; patchFavIcon $d ../$2 ; fi ;
done
}
commit() {
echo "Committing javadocs"
git add -A -f javadoc
git commit -m "Updated JavaDocs"
git push -fq > /dev/null
}
# Install parent and core
echo "Installing parent and core artifacts"
mvn install -N
cd core
mvn install -DskipTests=true
cd ../
build "core"
build "okhttp"
build "retrofit" failsafe-failsafe-parent-3.3.2/core/ 0000775 0000000 0000000 00000000000 14445610507 0017266 5 ustar 00root root 0000000 0000000 failsafe-failsafe-parent-3.3.2/core/pom.xml 0000664 0000000 0000000 00000001757 14445610507 0020615 0 ustar 00root root 0000000 0000000
4.0.0dev.failsafefailsafe-parent3.3.2failsafeFailsafe${project.groupId}.coreorg.moditectmoditect-maven-pluginmaven-jar-plugintest-jar
failsafe-failsafe-parent-3.3.2/core/src/ 0000775 0000000 0000000 00000000000 14445610507 0020055 5 ustar 00root root 0000000 0000000 failsafe-failsafe-parent-3.3.2/core/src/main/ 0000775 0000000 0000000 00000000000 14445610507 0021001 5 ustar 00root root 0000000 0000000 failsafe-failsafe-parent-3.3.2/core/src/main/java/ 0000775 0000000 0000000 00000000000 14445610507 0021722 5 ustar 00root root 0000000 0000000 failsafe-failsafe-parent-3.3.2/core/src/main/java/dev/ 0000775 0000000 0000000 00000000000 14445610507 0022500 5 ustar 00root root 0000000 0000000 failsafe-failsafe-parent-3.3.2/core/src/main/java/dev/failsafe/ 0000775 0000000 0000000 00000000000 14445610507 0024252 5 ustar 00root root 0000000 0000000 failsafe-failsafe-parent-3.3.2/core/src/main/java/dev/failsafe/AsyncExecution.java 0000664 0000000 0000000 00000004743 14445610507 0030066 0 ustar 00root root 0000000 0000000 /*
* Copyright 2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License
*/
package dev.failsafe;
import java.util.concurrent.CompletableFuture;
/**
* Allows asynchronous executions to record their results or complete an execution.
*
* @param result type
* @author Jonathan Halterman
*/
public interface AsyncExecution extends ExecutionContext {
/**
* Completes the execution and the associated {@code CompletableFuture}.
*
* @throws IllegalStateException if the execution is already recorded or complete
*/
void complete();
/**
* Returns whether the execution is complete or if it can be retried. An execution is considered complete only when
* all configured policies consider the execution complete.
*/
boolean isComplete();
/**
* Records an execution {@code result} or {@code exception} which triggers failure handling, if needed, by the
* configured policies. If policy handling is not possible or already complete, the resulting {@link
* CompletableFuture} is completed.
*
* @throws IllegalStateException if the most recent execution was already recorded or the execution is complete
*/
void record(R result, Throwable exception);
/**
* Records an execution {@code result} which triggers failure handling, if needed, by the configured policies. If
* policy handling is not possible or already complete, the resulting {@link CompletableFuture} is completed.
*
* @throws IllegalStateException if the most recent execution was already recorded or the execution is complete
*/
void recordResult(R result);
/**
* Records an {@code exception} which triggers failure handling, if needed, by the configured policies. If policy
* handling is not possible or already complete, the resulting {@link CompletableFuture} is completed.
*
* @throws IllegalStateException if the most recent execution was already recorded or the execution is complete
*/
void recordException(Throwable exception);
} failsafe-failsafe-parent-3.3.2/core/src/main/java/dev/failsafe/AsyncExecutionImpl.java 0000664 0000000 0000000 00000011061 14445610507 0030677 0 ustar 00root root 0000000 0000000 /*
* Copyright 2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License
*/
package dev.failsafe;
import dev.failsafe.internal.util.Assert;
import dev.failsafe.spi.*;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionException;
import java.util.function.Function;
/**
* AsyncExecution and AsyncExecutionInternal implementation.
*
* @param result type
* @author Jonathan Halterman
*/
final class AsyncExecutionImpl extends ExecutionImpl implements AsyncExecutionInternal {
// -- Cross-attempt state --
private final FailsafeFuture future;
private final boolean asyncExecution;
// The outermost function that executions begin with
private Function, CompletableFuture>> outerFn;
// -- Per-attempt state --
// Whether a policy executor completed post execution
private final boolean[] policyPostExecuted = new boolean[policyExecutors.size()];
// Whether a result has been recorded
private volatile boolean recorded;
AsyncExecutionImpl(List> policies, Scheduler scheduler, FailsafeFuture future, boolean asyncExecution,
Function, CompletableFuture>> innerFn) {
super(policies);
this.future = future;
this.asyncExecution = asyncExecution;
outerFn = asyncExecution ? Functions.toExecutionAware(innerFn) : innerFn;
outerFn = Functions.toAsync(outerFn, scheduler, future);
for (PolicyExecutor policyExecutor : policyExecutors)
outerFn = policyExecutor.applyAsync(outerFn, scheduler, future);
}
/**
* Create an async execution for a new attempt.
*/
private AsyncExecutionImpl(AsyncExecutionImpl execution) {
super(execution);
outerFn = execution.outerFn;
future = execution.future;
asyncExecution = execution.asyncExecution;
}
@Override
public void complete() {
Assert.state(!recorded, "The most recent execution has already been recorded or completed");
recorded = true;
// Guard against race with a timeout being set
synchronized (future) {
ExecutionResult result = this.result != null ? this.result : ExecutionResult.none();
complete(postExecute(result), null);
}
}
@Override
public boolean isComplete() {
return completed;
}
@Override
public void record(R result, Throwable exception) {
Assert.state(!recorded, "The most recent execution has already been recorded or completed");
recorded = true;
// Guard against race with a timeout being set
synchronized (future) {
if (!attemptRecorded) {
Assert.state(!completed, "Execution has already been completed");
record(new ExecutionResult<>(result, exception));
}
// Proceed with handling the recorded result
executeAsync();
}
}
@Override
public void recordResult(R result) {
record(result, null);
}
@Override
public void recordException(Throwable exception) {
record(null, exception);
}
@Override
public boolean isAsyncExecution() {
return asyncExecution;
}
@Override
public boolean isRecorded() {
return recorded;
}
@Override
public synchronized void setPostExecuted(int policyIndex) {
policyPostExecuted[policyIndex] = true;
}
@Override
public synchronized boolean isPostExecuted(int policyIndex) {
return policyPostExecuted[policyIndex];
}
@Override
public AsyncExecutionInternal copy() {
return new AsyncExecutionImpl<>(this);
}
/**
* Performs an asynchronous execution.
*/
void executeAsync() {
outerFn.apply(this).whenComplete(this::complete);
}
private void complete(ExecutionResult result, Throwable error) {
if (result == null && error == null)
return;
completed = true;
if (!future.isDone()) {
if (result != null)
future.completeResult(result);
else {
if (error instanceof CompletionException)
error = error.getCause();
future.completeResult(ExecutionResult.exception(error));
}
}
}
}
failsafe-failsafe-parent-3.3.2/core/src/main/java/dev/failsafe/Bulkhead.java 0000664 0000000 0000000 00000011010 14445610507 0026625 0 ustar 00root root 0000000 0000000 /*
* Copyright 2021 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License
*/
package dev.failsafe;
import dev.failsafe.internal.BulkheadImpl;
import java.time.Duration;
/**
* A bulkhead allows you to restrict concurrent executions as a way of preventing system overload.
*
* This class is threadsafe.
*
*
* @param result type
* @author Jonathan Halterman
* @see BulkheadConfig
* @see BulkheadBuilder
* @see BulkheadFullException
*/
public interface Bulkhead extends Policy {
/**
* Returns a Bulkhead for the {@code maxConcurrency} that has {@link BulkheadBuilder#withMaxWaitTime(Duration) zero
* wait}.
*
* @param maxConcurrency controls the max concurrent executions that are permitted within the bulkhead
*/
static BulkheadBuilder builder(int maxConcurrency) {
return new BulkheadBuilder<>(maxConcurrency);
}
/**
* Creates a new BulkheadBuilder that will be based on the {@code config}.
*/
static BulkheadBuilder builder(BulkheadConfig config) {
return new BulkheadBuilder<>(config);
}
/**
* Returns a Bulkhead for the {@code maxConcurrency} that has {@link BulkheadBuilder#withMaxWaitTime(Duration) zero
* wait}. Alias for {@code Bulkhead.builder(maxConcurrency).build()}. To configure additional options on a Bulkhead,
* use {@link #builder(int)} instead.
*
* @param maxConcurrency controls the max concurrent executions that are permitted within the bulkhead
* @see #builder(int)
*/
static Bulkhead of(int maxConcurrency) {
return new BulkheadImpl<>(new BulkheadConfig<>(maxConcurrency));
}
/**
* Returns the {@link BulkheadConfig} that the Bulkhead was built with.
*/
@Override
BulkheadConfig getConfig();
/**
* Attempts to acquire a permit to perform an execution against within the bulkhead, waiting until one is available or
* the thread is interrupted. After execution is complete, the permit should be {@link #releasePermit() released} back
* to the bulkhead.
*
* @throws InterruptedException if the current thread is interrupted while waiting to acquire a permit
* @see #tryAcquirePermit()
*/
void acquirePermit() throws InterruptedException;
/**
* Attempts to acquire a permit to perform an execution within the bulkhead, waiting up to the {@code maxWaitTime}
* until one is available, else throwing {@link BulkheadFullException} if a permit will not be available in time.
* After execution is complete, the permit should be {@link #releasePermit() released} back to the bulkhead.
*
* @throws NullPointerException if {@code maxWaitTime} is null
* @throws BulkheadFullException if the bulkhead cannot acquire a permit within the {@code maxWaitTime}
* @throws InterruptedException if the current thread is interrupted while waiting to acquire a permit
* @see #tryAcquirePermit(Duration)
*/
default void acquirePermit(Duration maxWaitTime) throws InterruptedException {
if (!tryAcquirePermit(maxWaitTime))
throw new BulkheadFullException(this);
}
/**
* Tries to acquire a permit to perform an execution within the bulkhead, returning immediately without waiting. After
* execution is complete, the permit should be {@link #releasePermit() released} back to the bulkhead.
*
* @return whether the requested {@code permits} are successfully acquired or not
*/
boolean tryAcquirePermit();
/**
* Tries to acquire a permit to perform an execution within the bulkhead, waiting up to the {@code maxWaitTime} until
* they are available. After execution is complete, the permit should be {@link #releasePermit() released} back to the
* bulkhead.
*
* @return whether a permit is successfully acquired
* @throws NullPointerException if {@code maxWaitTime} is null
* @throws InterruptedException if the current thread is interrupted while waiting to acquire a permit
*/
boolean tryAcquirePermit(Duration maxWaitTime) throws InterruptedException;
/**
* Releases a permit to execute.
*/
void releasePermit();
}
failsafe-failsafe-parent-3.3.2/core/src/main/java/dev/failsafe/BulkheadBuilder.java 0000664 0000000 0000000 00000004026 14445610507 0030145 0 ustar 00root root 0000000 0000000 /*
* Copyright 2021 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License
*/
package dev.failsafe;
import dev.failsafe.internal.BulkheadImpl;
import dev.failsafe.internal.util.Assert;
import java.time.Duration;
/**
* Builds {@link Bulkhead} instances.
*
* This class is not threadsafe.
*
*
* @param result type
* @author Jonathan Halterman
* @see BulkheadConfig
* @see BulkheadFullException
*/
public class BulkheadBuilder extends PolicyBuilder, BulkheadConfig, R> {
BulkheadBuilder(int maxConcurrency) {
super(new BulkheadConfig<>(maxConcurrency));
}
BulkheadBuilder(BulkheadConfig config) {
super(new BulkheadConfig<>(config));
}
/**
* Builds a new {@link Bulkhead} using the builder's configuration.
*/
public Bulkhead build() {
return new BulkheadImpl<>(new BulkheadConfig<>(config));
}
/**
* Configures the {@code maxWaitTime} to wait for permits to be available. If permits cannot be acquired before the
* {@code maxWaitTime} is exceeded, then the bulkhead will throw {@link BulkheadFullException}.
*
* This setting only applies when the resulting Bulkhead is used with the {@link Failsafe} class. It does not apply
* when the Bulkhead is used in a standalone way.
*
*
* @throws NullPointerException if {@code maxWaitTime} is null
*/
public BulkheadBuilder withMaxWaitTime(Duration maxWaitTime) {
config.maxWaitTime = Assert.notNull(maxWaitTime, "maxWaitTime");
return this;
}
}
failsafe-failsafe-parent-3.3.2/core/src/main/java/dev/failsafe/BulkheadConfig.java 0000664 0000000 0000000 00000003476 14445610507 0027774 0 ustar 00root root 0000000 0000000 /*
* Copyright 2021 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License
*/
package dev.failsafe;
import java.time.Duration;
/**
* Configuration for a {@link Bulkhead}.
*
* @param result type
* @author Jonathan Halterman
*/
public class BulkheadConfig extends PolicyConfig {
int maxConcurrency;
Duration maxWaitTime;
BulkheadConfig(int maxConcurrency) {
this.maxConcurrency = maxConcurrency;
maxWaitTime = Duration.ZERO;
}
BulkheadConfig(BulkheadConfig config) {
super(config);
maxConcurrency = config.maxConcurrency;
maxWaitTime = config.maxWaitTime;
}
/**
* Returns that max concurrent executions that are permitted within the bulkhead.
*
* @see Bulkhead#builder(int)
*/
public int getMaxConcurrency() {
return maxConcurrency;
}
/**
* Returns the max time to wait for permits to be available. If permits cannot be acquired before the max wait time is
* exceeded, then the bulkhead will throw {@link BulkheadFullException}.
*
* This setting only applies when the Bulkhead is used with the {@link Failsafe} class. It does not apply when the
* Bulkhead is used in a standalone way.
*
*
* @see BulkheadBuilder#withMaxWaitTime(Duration)
*/
public Duration getMaxWaitTime() {
return maxWaitTime;
}
}
failsafe-failsafe-parent-3.3.2/core/src/main/java/dev/failsafe/BulkheadFullException.java 0000664 0000000 0000000 00000002151 14445610507 0031335 0 ustar 00root root 0000000 0000000 /*
* Copyright 2021 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License
*/
package dev.failsafe;
/**
* Thrown when an execution is attempted against a {@link Bulkhead} that is full.
*
* @author Jonathan Halterman
*/
public class BulkheadFullException extends FailsafeException {
private static final long serialVersionUID = 1L;
private final Bulkhead> bulkhead;
public BulkheadFullException(Bulkhead> bulkhead) {
this.bulkhead = bulkhead;
}
/** Returns the {@link Bulkhead} that caused the exception. */
public Bulkhead> getBulkhead() {
return bulkhead;
}
}
failsafe-failsafe-parent-3.3.2/core/src/main/java/dev/failsafe/Call.java 0000664 0000000 0000000 00000004300 14445610507 0025765 0 ustar 00root root 0000000 0000000 /*
* Copyright 2022 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License
*/
package dev.failsafe;
import dev.failsafe.function.CheckedRunnable;
/**
* A call that can perform Failsafe executions and can be cancelled. Cancellations are propagated to any {@link
* ExecutionContext#onCancel(CheckedRunnable) cancelCallback} that is registered. Useful for integrating with libraries
* that support cancellation.
*
* To perform cancellable async executions, use the {@link FailsafeExecutor} async methods.
*
*
* @param result type
* @author Jonathan Halterman
*/
public interface Call {
/**
* Executes the call until a successful result is returned or the configured policies are exceeded.
*
* @throws FailsafeException if the execution fails with a checked Exception. {@link FailsafeException#getCause()} can
* be used to learn the underlying checked exception.
*/
R execute();
/**
* Cancels a synchronous execution and calls the most recent {@link ExecutionContext#onCancel(CheckedRunnable)
* cancelCallback} that was registered. The execution is still allowed to complete and return a result. In addition to
* using a {@link ExecutionContext#onCancel(CheckedRunnable) cancelCallback}, executions can cooperate with
* cancellation by checking {@link ExecutionContext#isCancelled()}.
*
* @param mayInterruptIfRunning whether the execution should be interrupted
* @return whether cancellation was successful or not. Returns {@code false} if the execution was already cancelled or
* completed.
*/
boolean cancel(boolean mayInterruptIfRunning);
/**
* Returns whether the call has been cancelled.
*/
boolean isCancelled();
}
failsafe-failsafe-parent-3.3.2/core/src/main/java/dev/failsafe/CallImpl.java 0000664 0000000 0000000 00000002420 14445610507 0026610 0 ustar 00root root 0000000 0000000 /*
* Copyright 2022 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License
*/
package dev.failsafe;
/**
* A call implementation that delegates to an execution.
*
* @param result type
* @author Jonathan Halterman
*/
class CallImpl implements Call {
private volatile SyncExecutionImpl execution;
void setExecution(SyncExecutionImpl execution) {
this.execution = execution;
}
@Override
public R execute() {
return execution.executeSync();
}
@Override
public boolean cancel(boolean mayInterruptIfRunning) {
boolean result = execution.cancel();
if (mayInterruptIfRunning)
execution.interrupt();
return result;
}
@Override
public boolean isCancelled() {
return execution.isCancelled();
}
}
failsafe-failsafe-parent-3.3.2/core/src/main/java/dev/failsafe/CircuitBreaker.java 0000664 0000000 0000000 00000021570 14445610507 0030020 0 ustar 00root root 0000000 0000000 /*
* Copyright 2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License
*/
package dev.failsafe;
import java.time.Duration;
/**
* A circuit breaker temporarily blocks execution when a configured number of failures are exceeded.
*
* Circuit breakers have three states: closed, open, and half-open. When a circuit breaker is in
* the closed (initial) state, executions are allowed. If a {@link CircuitBreakerBuilder#withFailureThreshold(int)
* configurable number} of failures occur, optionally over some {@link CircuitBreakerBuilder#withFailureThreshold(int,
* Duration) time period}, the circuit breaker transitions to the open state. In the open state a circuit
* breaker will fail executions with {@link CircuitBreakerOpenException}. After a {@link
* CircuitBreakerBuilder#withDelay(Duration) configurable delay}, the circuit breaker will transition to a
* half-open state. In the
* half-open state a {@link CircuitBreakerBuilder#withSuccessThreshold(int) configurable number} of trial
* executions will be allowed, after which the circuit breaker will transition back to closed or open
* depending on how many were successful.
*
*
* A circuit breaker can be count based or time based:
*
*
Count based circuit breakers will transition between states when recent execution results exceed a threshold.
*
Time based circuit breakers will transition between states when recent execution results exceed a threshold
* within a time period.
*
*
*
A minimum number of executions must be performed in order for a state transition to occur. Time based circuit
* breakers use a sliding window to aggregate execution results. The window is divided into {@code 10} time slices,
* each representing 1/10th of the {@link CircuitBreakerConfig#getFailureThresholdingPeriod() failureThresholdingPeriod}.
* As time progresses, statistics for old time slices are gradually discarded, which smoothes the calculation of
* success and failure rates.
*
* This class is threadsafe.
*
*
* @param result type
* @author Jonathan Halterman
* @see CircuitBreakerConfig
* @see CircuitBreakerBuilder
* @see CircuitBreakerOpenException
*/
public interface CircuitBreaker extends Policy {
/**
* Creates a CircuitBreakerBuilder that by default will build a count based circuit breaker that opens after a {@link
* CircuitBreakerBuilder#withFailureThreshold(int) single failure}, closes after a {@link
* CircuitBreakerBuilder#withSuccessThreshold(int) single success}, and has a 1 minute {@link
* CircuitBreakerBuilder#withDelay(Duration) delay}, unless configured otherwise.
*
* @see #ofDefaults()
*/
static CircuitBreakerBuilder builder() {
return new CircuitBreakerBuilder<>();
}
/**
* Creates a new CircuitBreakerBuilder that will be based on the {@code config}.
*/
static CircuitBreakerBuilder builder(CircuitBreakerConfig config) {
return new CircuitBreakerBuilder<>(config);
}
/**
* Creates a count based CircuitBreaker that opens after one {@link CircuitBreakerBuilder#withFailureThreshold(int)
* failure}, half-opens after a one minute {@link CircuitBreakerBuilder#withDelay(Duration) delay}, and closes after one
* {@link CircuitBreakerBuilder#withSuccessThreshold(int) success}. To configure additional options on a
* CircuitBreaker, use {@link #builder()} instead.
*
* @see #builder()
*/
static CircuitBreaker ofDefaults() {
return CircuitBreaker.builder().build();
}
/**
* The state of the circuit.
*/
enum State {
/** The circuit is closed and fully functional, allowing executions to occur. */
CLOSED,
/** The circuit is opened and not allowing executions to occur. */
OPEN,
/** The circuit is temporarily allowing executions to occur. */
HALF_OPEN
}
/**
* Returns the {@link CircuitBreakerConfig} that the CircuitBreaker was built with.
*/
@Override
CircuitBreakerConfig getConfig();
/**
* Attempts to acquire a permit for the circuit breaker and throws {@link CircuitBreakerOpenException} if a permit
* could not be acquired. Permission will be automatically released when a result or failure is recorded.
*
* @throws CircuitBreakerOpenException if the circuit breaker is in a half-open state and no permits remain according
* to the configured success or failure thresholding capacity.
* @see #tryAcquirePermit()
* @see #recordResult(Object)
* @see #recordException(Throwable)
* @see #recordSuccess()
* @see #recordFailure()
*/
default void acquirePermit() {
if (!tryAcquirePermit())
throw new CircuitBreakerOpenException(this);
}
/**
* Tries to acquire a permit to use the circuit breaker and returns whether a permit was acquired. Permission will be
* automatically released when a result or failure is recorded.
*
* @see #recordResult(Object)
* @see #recordException(Throwable)
* @see #recordSuccess()
* @see #recordFailure()
*/
boolean tryAcquirePermit();
/**
* Opens the circuit.
*/
void open();
/**
* Closes the circuit.
*/
void close();
/**
* Half-opens the circuit.
*/
void halfOpen();
/**
* Gets the state of the circuit.
*/
State getState();
/**
* Returns the number of executions recorded in the current state when the state is CLOSED or HALF_OPEN. When the
* state is OPEN, returns the executions recorded during the previous CLOSED state.
*
* For count based thresholding, the max number of executions is limited to the execution threshold. For time based
* thresholds, the number of executions may vary within the thresholding period.
*
*/
int getExecutionCount();
/**
* When in the OPEN state, returns the remaining delay until the circuit is half-opened and allows another execution,
* else returns {@code Duration.ZERO}.
*/
Duration getRemainingDelay();
/**
* Returns the number of failures recorded in the current state when the state is CLOSED or HALF_OPEN. When the state
* is OPEN, returns the failures recorded during the previous CLOSED state.
*
* For count based thresholds, the max number of failures is based on the {@link
* CircuitBreakerConfig#getFailureThreshold() failure threshold}. For time based thresholds, the number of failures
* may vary within the {@link CircuitBreakerConfig#getFailureThresholdingPeriod() failure thresholding period}.
*
*/
long getFailureCount();
/**
* The percentage rate of failed executions, from 0 to 100, in the current state when the state is CLOSED or
* HALF_OPEN. When the state is OPEN, returns the rate recorded during the previous CLOSED state.
*
* The rate is based on the configured {@link CircuitBreakerConfig#getFailureThresholdingCapacity() failure
* thresholding capacity}.
*
*/
int getFailureRate();
/**
* Returns the number of successes recorded in the current state when the state is CLOSED or HALF_OPEN. When the state
* is OPEN, returns the successes recorded during the previous CLOSED state.
*
* The max number of successes is based on the {@link CircuitBreakerConfig#getSuccessThreshold() success threshold}.
*
*/
int getSuccessCount();
/**
* The percentage rate of successful executions, from 0 to 100, in the current state when the state is CLOSED or
* HALF_OPEN. When the state is OPEN, returns the rate recorded during the previous CLOSED state.
*
* The rate is based on the configured {@link CircuitBreakerConfig#getSuccessThresholdingCapacity() success
* thresholding capacity}.
*
*/
int getSuccessRate();
/**
* Returns whether the circuit is closed.
*/
boolean isClosed();
/**
* Returns whether the circuit is half open.
*/
boolean isHalfOpen();
/**
* Returns whether the circuit is open.
*/
boolean isOpen();
/**
* Records an execution failure.
*/
void recordFailure();
/**
* Records an {@code exception} as a success or failure based on the failure configuration.
*/
void recordException(Throwable exception);
/**
* Records an execution {@code result} as a success or failure based on the failure configuration.
*/
void recordResult(R result);
/**
* Records an execution success.
*/
void recordSuccess();
}
failsafe-failsafe-parent-3.3.2/core/src/main/java/dev/failsafe/CircuitBreakerBuilder.java 0000664 0000000 0000000 00000036207 14445610507 0031332 0 ustar 00root root 0000000 0000000 /*
* Copyright 2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License
*/
package dev.failsafe;
import dev.failsafe.event.CircuitBreakerStateChangedEvent;
import dev.failsafe.event.EventListener;
import dev.failsafe.function.CheckedBiPredicate;
import dev.failsafe.function.CheckedPredicate;
import dev.failsafe.internal.CircuitBreakerImpl;
import dev.failsafe.internal.util.Assert;
import dev.failsafe.internal.util.Durations;
import java.time.Duration;
/**
* Builds {@link CircuitBreaker} instances.
*
*
By default, any exception is considered a failure and will be handled by the policy. You can override this by
* specifying your own {@code handle} conditions. The default exception handling condition will only be overridden by
* another condition that handles exceptions such as {@link #handle(Class)} or {@link #handleIf(CheckedBiPredicate)}.
* Specifying a condition that only handles results, such as {@link #handleResult(Object)} or
* {@link #handleResultIf(CheckedPredicate)} will not replace the default exception handling condition.
*
If multiple {@code handle} conditions are specified, any condition that matches an execution result or exception
* will trigger policy handling.
*
*
* Note:
*
*
This class extends {@link DelayablePolicyBuilder} and {@link FailurePolicyBuilder} which offer additional configuration.
*
This class is not threadsafe.
*
*
*
* @param result type
* @author Jonathan Halterman
* @see CircuitBreaker
* @see CircuitBreakerConfig
* @see CircuitBreakerOpenException
*/
public class CircuitBreakerBuilder
extends DelayablePolicyBuilder, CircuitBreakerConfig, R>
implements PolicyListeners, R> {
CircuitBreakerBuilder() {
super(new CircuitBreakerConfig<>());
config.delay = Duration.ofMinutes(1);
config.failureThreshold = 1;
config.failureThresholdingCapacity = 1;
}
CircuitBreakerBuilder(CircuitBreakerConfig config) {
super(new CircuitBreakerConfig<>(config));
}
/**
* Builds a new {@link CircuitBreaker} using the builder's configuration.
*/
public CircuitBreaker build() {
return new CircuitBreakerImpl<>(new CircuitBreakerConfig<>(config));
}
/**
* Calls the {@code listener} when the circuit is closed.
*
Note: Any exceptions that are thrown from within the {@code listener} are ignored.
*
* @throws NullPointerException if {@code listener} is null
*/
public CircuitBreakerBuilder onClose(EventListener listener) {
config.closeListener = Assert.notNull(listener, "runnable");
return this;
}
/**
* Calls the {@code listener} when the circuit is half-opened.
*
Note: Any exceptions that are thrown within the {@code listener} are ignored.
*
* @throws NullPointerException if {@code listener} is null
*/
public CircuitBreakerBuilder onHalfOpen(EventListener listener) {
config.halfOpenListener = Assert.notNull(listener, "runnable");
return this;
}
/**
* Calls the {@code listener} when the circuit is opened.
*
Note: Any exceptions that are thrown within the {@code listener} are ignored.
*
* @throws NullPointerException if {@code listener} is null
*/
public CircuitBreakerBuilder onOpen(EventListener listener) {
config.openListener = Assert.notNull(listener, "listener");
return this;
}
/**
* Sets the {@code delay} to wait in OPEN state before transitioning to half-open.
*
* @throws NullPointerException if {@code delay} is null
* @throws IllegalArgumentException if {@code delay} < 0
*/
public CircuitBreakerBuilder withDelay(Duration delay) {
Assert.notNull(delay, "delay");
delay = Durations.ofSafeNanos(delay);
Assert.isTrue(delay.toNanos() >= 0, "delay must be >= 0");
config.delay = delay;
return this;
}
/**
* Configures count based failure thresholding by setting the number of consecutive failures that must occur when in a
* CLOSED state in order to open the circuit.
*
* If a {@link #withSuccessThreshold(int) success threshold} is not configured, the {@code failureThreshold} will also
* be used when the circuit breaker is in a HALF_OPEN state to determine whether to transition back to OPEN or
* CLOSED.
*
*
* @param failureThreshold The number of consecutive failures that must occur in order to open the circuit
* @throws IllegalArgumentException if {@code failureThreshold} < 1
* @see CircuitBreakerConfig#getFailureThreshold()
*/
public CircuitBreakerBuilder withFailureThreshold(int failureThreshold) {
return withFailureThreshold(failureThreshold, failureThreshold);
}
/**
* Configures count based failure thresholding by setting the ratio of failures to executions that must occur when in
* a CLOSED state in order to open the circuit. For example: 5, 10 would open the circuit if 5 out of the last 10
* executions result in a failure.
*
* If a {@link #withSuccessThreshold(int) success threshold} is not configured, the {@code failureThreshold} and
* {@code failureThresholdingCapacity} will also be used when the circuit breaker is in a HALF_OPEN state to determine
* whether to transition back to OPEN or CLOSED.
*
*
* @param failureThreshold The number of failures that must occur in order to open the circuit
* @param failureThresholdingCapacity The capacity for storing execution results when performing failure thresholding
* @throws IllegalArgumentException if {@code failureThreshold} < 1, {@code failureThresholdingCapacity} < 1, or
* {@code failureThreshold} > {@code failureThresholdingCapacity}
* @see CircuitBreakerConfig#getFailureThreshold()
* @see CircuitBreakerConfig#getFailureExecutionThreshold()
*/
public CircuitBreakerBuilder withFailureThreshold(int failureThreshold, int failureThresholdingCapacity) {
Assert.isTrue(failureThreshold >= 1, "failureThreshold must be >= 1");
Assert.isTrue(failureThresholdingCapacity >= 1, "failureThresholdingCapacity must be >= 1");
Assert.isTrue(failureThresholdingCapacity >= failureThreshold,
"failureThresholdingCapacity must be >= failureThreshold");
config.failureThreshold = failureThreshold;
config.failureThresholdingCapacity = failureThresholdingCapacity;
return this;
}
/**
* Configures time based failure thresholding by setting the number of failures that must occur within the {@code
* failureThresholdingPeriod} when in a CLOSED state in order to open the circuit.
*
* If a {@link #withSuccessThreshold(int) success threshold} is not configured, the {@code failureThreshold} will also
* be used when the circuit breaker is in a HALF_OPEN state to determine whether to transition back to OPEN or
* CLOSED.
*
*
* @param failureThreshold The number of failures that must occur within the {@code failureThresholdingPeriod} in
* order to open the circuit
* @param failureThresholdingPeriod The period during which failures are compared to the {@code failureThreshold}
* @throws NullPointerException if {@code failureThresholdingPeriod} is null
* @throws IllegalArgumentException if {@code failureThreshold} < 1 or {@code failureThresholdingPeriod} < 10 ms
* @see CircuitBreakerConfig#getFailureThreshold()
* @see CircuitBreakerConfig#getFailureThresholdingPeriod()
*/
public CircuitBreakerBuilder withFailureThreshold(int failureThreshold, Duration failureThresholdingPeriod) {
return withFailureThreshold(failureThreshold, failureThreshold, failureThresholdingPeriod);
}
/**
* Configures time based failure thresholding by setting the number of failures that must occur within the {@code
* failureThresholdingPeriod} when in a CLOSED state in order to open the circuit. The number of executions must also
* exceed the {@code failureExecutionThreshold} within the {@code failureThresholdingPeriod} when in the CLOSED state
* before the circuit can be opened.
*
* If a {@link #withSuccessThreshold(int) success threshold} is not configured, the {@code failureThreshold} will also
* be used when the circuit breaker is in a HALF_OPEN state to determine whether to transition back to OPEN or
* CLOSED.
*
*
* @param failureThreshold The number of failures that must occur within the {@code failureThresholdingPeriod} in
* order to open the circuit
* @param failureExecutionThreshold The minimum number of executions that must occur within the {@code
* failureThresholdingPeriod} when in the CLOSED state before the circuit can be opened
* @param failureThresholdingPeriod The period during which failures are compared to the {@code failureThreshold}
* @throws NullPointerException if {@code failureThresholdingPeriod} is null
* @throws IllegalArgumentException if {@code failureThreshold} < 1, {@code failureExecutionThreshold} < 1, {@code
* failureThreshold} > {@code failureExecutionThreshold}, or {@code failureThresholdingPeriod} < 10 ms
* @see CircuitBreakerConfig#getFailureThreshold()
* @see CircuitBreakerConfig#getFailureExecutionThreshold()
* @see CircuitBreakerConfig#getFailureThresholdingPeriod()
*/
public CircuitBreakerBuilder withFailureThreshold(int failureThreshold, int failureExecutionThreshold,
Duration failureThresholdingPeriod) {
Assert.isTrue(failureThreshold >= 1, "failureThreshold must be >= 1");
Assert.isTrue(failureExecutionThreshold >= failureThreshold,
"failureExecutionThreshold must be >= failureThreshold");
assertFailureExecutionThreshold(failureExecutionThreshold);
assertFailureThresholdingPeriod(failureThresholdingPeriod);
config.failureThreshold = failureThreshold;
config.failureThresholdingCapacity = failureThreshold;
config.failureExecutionThreshold = failureExecutionThreshold;
config.failureThresholdingPeriod = failureThresholdingPeriod;
return this;
}
/**
* Configures time based failure rate thresholding by setting the percentage rate of failures, from 1 to 100, that
* must occur within the rolling {@code failureThresholdingPeriod} when in a CLOSED state in order to open the
* circuit. The number of executions must also exceed the {@code failureExecutionThreshold} within the {@code
* failureThresholdingPeriod} before the circuit can be opened.
*
* If a {@link #withSuccessThreshold(int) success threshold} is not configured, the {@code failureExecutionThreshold}
* will also be used when the circuit breaker is in a HALF_OPEN state to determine whether to transition back to open
* or closed.
*
*
* @param failureRateThreshold The percentage rate of failures, from 1 to 100, that must occur in order to open the
* circuit
* @param failureExecutionThreshold The minimum number of executions that must occur within the {@code
* failureThresholdingPeriod} when in the CLOSED state before the circuit can be opened, or in the HALF_OPEN state
* before it can be re-opened or closed
* @param failureThresholdingPeriod The period during which failures are compared to the {@code failureThreshold}
* @throws NullPointerException if {@code failureThresholdingPeriod} is null
* @throws IllegalArgumentException if {@code failureRateThreshold} < 1 or > 100, {@code failureExecutionThreshold} <
* 1, or {@code failureThresholdingPeriod} < 10 ms
* @see CircuitBreakerConfig#getFailureRateThreshold()
* @see CircuitBreakerConfig#getFailureExecutionThreshold()
* @see CircuitBreakerConfig#getFailureThresholdingPeriod()
*/
public CircuitBreakerBuilder withFailureRateThreshold(int failureRateThreshold, int failureExecutionThreshold,
Duration failureThresholdingPeriod) {
Assert.isTrue(failureRateThreshold >= 1 && failureRateThreshold <= 100,
"failureRateThreshold must be between 1 and 100");
assertFailureExecutionThreshold(failureExecutionThreshold);
assertFailureThresholdingPeriod(failureThresholdingPeriod);
config.failureRateThreshold = failureRateThreshold;
config.failureExecutionThreshold = failureExecutionThreshold;
config.failureThresholdingPeriod = failureThresholdingPeriod;
return this;
}
private void assertFailureExecutionThreshold(int failureExecutionThreshold) {
Assert.isTrue(failureExecutionThreshold >= 1, "failureExecutionThreshold must be >= 1");
}
private void assertFailureThresholdingPeriod(Duration failureThresholdingPeriod) {
Assert.notNull(failureThresholdingPeriod, "failureThresholdingPeriod");
Assert.isTrue(failureThresholdingPeriod.toMillis() >= 10, "failureThresholdingPeriod must be >= 10 ms");
}
/**
* Configures count based success thresholding by setting the number of consecutive successful executions that must
* occur when in a HALF_OPEN state in order to close the circuit, else the circuit is re-opened when a failure
* occurs.
*
* @param successThreshold The number of consecutive successful executions that must occur in order to open the
* circuit
* @throws IllegalArgumentException if {@code successThreshold} < 1
* @see CircuitBreakerConfig#getSuccessThreshold()
*/
public CircuitBreakerBuilder withSuccessThreshold(int successThreshold) {
return withSuccessThreshold(successThreshold, successThreshold);
}
/**
* Configures count based success thresholding by setting the ratio of successful executions that must occur when in a
* HALF_OPEN state in order to close the circuit. For example: 5, 10 would close the circuit if 5 out of the last 10
* executions were successful.
*
* @param successThreshold The number of successful executions that must occur in order to open the circuit
* @param successThresholdingCapacity The capacity for storing execution results when performing success thresholding
* @throws IllegalArgumentException if {@code successThreshold} < 1, {@code successThresholdingCapacity} < 1, or
* {@code successThreshold} > {@code successThresholdingCapacity}
* @see CircuitBreakerConfig#getSuccessThreshold()
* @see CircuitBreakerConfig#getSuccessThresholdingCapacity()
*/
public CircuitBreakerBuilder withSuccessThreshold(int successThreshold, int successThresholdingCapacity) {
Assert.isTrue(successThreshold >= 1, "successThreshold must be >= 1");
Assert.isTrue(successThresholdingCapacity >= 1, "successThresholdingCapacity must be >= 1");
Assert.isTrue(successThresholdingCapacity >= successThreshold,
"successThresholdingCapacity must be >= successThreshold");
config.successThreshold = successThreshold;
config.successThresholdingCapacity = successThresholdingCapacity;
return this;
}
}
failsafe-failsafe-parent-3.3.2/core/src/main/java/dev/failsafe/CircuitBreakerConfig.java 0000664 0000000 0000000 00000015164 14445610507 0031150 0 ustar 00root root 0000000 0000000 /*
* Copyright 2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License
*/
package dev.failsafe;
import dev.failsafe.event.EventListener;
import dev.failsafe.event.CircuitBreakerStateChangedEvent;
import java.time.Duration;
/**
* Configuration for a {@link CircuitBreaker}.
*
* This class is threadsafe.
*
*
* @param result type
* @author Jonathan Halterman
* @see CircuitBreakerBuilder
*/
public class CircuitBreakerConfig extends DelayablePolicyConfig {
// Failure config
int failureThreshold;
int failureRateThreshold;
int failureThresholdingCapacity;
int failureExecutionThreshold;
Duration failureThresholdingPeriod;
// Success config
int successThreshold;
int successThresholdingCapacity;
// Listeners
EventListener openListener;
EventListener halfOpenListener;
EventListener closeListener;
CircuitBreakerConfig() {
}
CircuitBreakerConfig(CircuitBreakerConfig config) {
super(config);
failureThreshold = config.failureThreshold;
failureRateThreshold = config.failureRateThreshold;
failureThresholdingCapacity = config.failureThresholdingCapacity;
failureExecutionThreshold = config.failureExecutionThreshold;
failureThresholdingPeriod = config.failureThresholdingPeriod;
successThreshold = config.successThreshold;
successThresholdingCapacity = config.successThresholdingCapacity;
openListener = config.openListener;
halfOpenListener = config.halfOpenListener;
closeListener = config.closeListener;
}
/**
* Returns the delay before allowing another execution on the circuit. Defaults to 1 minute.
*
* @see CircuitBreakerBuilder#withDelay(Duration)
* @see CircuitBreaker#getRemainingDelay()
*/
public Duration getDelay() {
return delay;
}
/**
* Gets the number of failures that must occur within the {@link #getFailureThresholdingCapacity() failure
* thresholding capacity} when in a CLOSED or HALF_OPEN state in order to open the circuit. Returns {@code 1} by
* default.
*
* @see CircuitBreakerBuilder#withFailureThreshold(int)
* @see CircuitBreakerBuilder#withFailureThreshold(int, int)
*/
public int getFailureThreshold() {
return failureThreshold;
}
/**
* Returns the rolling capacity for storing execution results when performing failure thresholding in the CLOSED or
* HALF_OPEN states. {@code 1} by default. Only the most recent executions that fit within this capacity contribute to
* thresholding decisions.
*
* @see CircuitBreakerBuilder#withFailureThreshold(int)
* @see CircuitBreakerBuilder#withFailureThreshold(int, int)
*/
public int getFailureThresholdingCapacity() {
return failureThresholdingCapacity;
}
/**
* Used with time based thresholding. Returns percentage rate of failures, from 1 to 100, that must occur when in a
* CLOSED or HALF_OPEN state in order to open the circuit, else {@code 0} if failure rate thresholding is not
* configured.
*
* @see CircuitBreakerBuilder#withFailureRateThreshold(int, int, Duration)
*/
public int getFailureRateThreshold() {
return failureRateThreshold;
}
/**
* Used with time based thresholding. Returns the rolling time period during which failure thresholding is performed
* when in the CLOSED state, else {@code null} if time based failure thresholding is not configured. Only the most
* recent executions that occurred within this rolling time period contribute to thresholding decisions.
*
* @see CircuitBreakerBuilder#withFailureThreshold(int, Duration)
* @see CircuitBreakerBuilder#withFailureThreshold(int, int, Duration)
* @see CircuitBreakerBuilder#withFailureRateThreshold(int, int, Duration)
*/
public Duration getFailureThresholdingPeriod() {
return failureThresholdingPeriod;
}
/**
* Used with time based thresholding. Returns the minimum number of executions that must be recorded in the CLOSED
* state before the breaker can be opened. For {@link CircuitBreakerBuilder#withFailureRateThreshold(int, int,
* Duration) failure rate thresholding} this also determines the minimum number of executions that must be recorded in
* the HALF_OPEN state. Returns {@code 0} by default.
*
* @see CircuitBreakerBuilder#withFailureThreshold(int, int, Duration)
* @see CircuitBreakerBuilder#withFailureRateThreshold(int, int, Duration)
*/
public int getFailureExecutionThreshold() {
return failureExecutionThreshold;
}
/**
* Gets the number of successes that must occur within the {@link #getSuccessThresholdingCapacity() success
* thresholding capacity} when in a HALF_OPEN state in order to open the circuit. Returns {@code 0} by default, in
* which case the {@link #getFailureThreshold() failure threshold} is used instead.
*
* @see CircuitBreakerBuilder#withSuccessThreshold(int)
* @see CircuitBreakerBuilder#withSuccessThreshold(int, int)
*/
public int getSuccessThreshold() {
return successThreshold;
}
/**
* Returns the rolling capacity for storing execution results when performing success thresholding in the HALF_OPEN
* state. Only the most recent executions that fit within this capacity contribute to thresholding decisions.
*
* @see CircuitBreakerBuilder#withSuccessThreshold(int)
* @see CircuitBreakerBuilder#withSuccessThreshold(int, int)
*/
public int getSuccessThresholdingCapacity() {
return successThresholdingCapacity;
}
/**
* Returns the open event listener.
*
* @see CircuitBreakerBuilder#onOpen(EventListener)
*/
public EventListener getOpenListener() {
return openListener;
}
/**
* Returns the half-open event listener.
*
* @see CircuitBreakerBuilder#onHalfOpen(EventListener)
*/
public EventListener getHalfOpenListener() {
return halfOpenListener;
}
/**
* Returns the close event listener.
*
* @see CircuitBreakerBuilder#onClose(EventListener)
*/
public EventListener getCloseListener() {
return closeListener;
}
}
failsafe-failsafe-parent-3.3.2/core/src/main/java/dev/failsafe/CircuitBreakerOpenException.java 0000664 0000000 0000000 00000002267 14445610507 0032523 0 ustar 00root root 0000000 0000000 /*
* Copyright 2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License
*/
package dev.failsafe;
/**
* Thrown when an execution is attempted against a {@link CircuitBreaker} that is open.
*
* @author Jonathan Halterman
*/
public class CircuitBreakerOpenException extends FailsafeException {
private static final long serialVersionUID = 1L;
private final CircuitBreaker> circuitBreaker;
public CircuitBreakerOpenException(CircuitBreaker> circuitBreaker) {
this.circuitBreaker = circuitBreaker;
}
/** Returns the {@link CircuitBreaker} that caused the exception. */
public CircuitBreaker> getCircuitBreaker() {
return circuitBreaker;
}
}
failsafe-failsafe-parent-3.3.2/core/src/main/java/dev/failsafe/DelayablePolicyBuilder.java 0000664 0000000 0000000 00000013440 14445610507 0031470 0 ustar 00root root 0000000 0000000 /*
* Copyright 2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License
*/
package dev.failsafe;
import dev.failsafe.function.ContextualSupplier;
import dev.failsafe.internal.util.Assert;
import java.time.Duration;
/**
* A builder of policies that can be delayed between executions.
*
* @param self type
* @param config type
* @param result type
* @author Jonathan Halterman
*/
public abstract class DelayablePolicyBuilder, R>
extends FailurePolicyBuilder {
protected DelayablePolicyBuilder(C config) {
super(config);
}
/**
* Sets the {@code delay} to occur between execution attempts.
*
* @throws NullPointerException if {@code delay} is null
* @throws IllegalArgumentException if {@code delay} <= 0
*/
@SuppressWarnings("unchecked")
public S withDelay(Duration delay) {
Assert.notNull(delay, "delay");
Assert.isTrue(delay.toNanos() > 0, "delay must be greater than 0");
config.delay = delay;
return (S) this;
}
/**
* Sets the {@code delayFunction} that computes the next delay before allowing another execution.
*
*
* The {@code delayFunction} must complete quickly, not have side-effects, and always return the same result for the
* same input. Exceptions thrown by the {@code delayFunction} method will not be handled and will
* cause Failsafe's execution to abort.
*
*
* Notes:
*
*
A negative return value will cause Failsafe to use a configured fixed or backoff delay
*
Any configured jitter is still applied to DelayFunction provided values
*
Any configured max duration is still applied to DelayFunction provided values
*
The {@link ExecutionContext} that is provided to the {@code delayFunction} may be {@code null} if the prior execution
* exception was manually recorded outside of a Failsafe execution.
*
*
*
* @throws NullPointerException if {@code delayFunction} is null
*/
@SuppressWarnings("unchecked")
public S withDelayFn(ContextualSupplier delayFunction) {
Assert.notNull(delayFunction, "delayFunction");
config.delayFn = delayFunction;
return (S) this;
}
/**
* Sets the {@code delayFunction} that computes the next delay before allowing another execution. Delays will only
* occur for exceptions that are assignable from the {@code exception}.
*
* The {@code delayFunction} must complete quickly, not have side-effects, and always return the same result for the
* same input. Exceptions thrown by the {@code delayFunction} method will not be handled and will
* cause Failsafe's execution to abort.
*
*
* Notes:
*
*
A negative return value will cause Failsafe to use a configured fixed or backoff delay
*
Any configured jitter is still applied to DelayFunction provided values
*
Any configured max duration is still applied to DelayFunction provided values
*
The {@link ExecutionContext} that is provided to the {@code delayFunction} may be {@code null} if the prior execution
* exception was manually recorded outside of a Failsafe execution.
*
*
*
* @param delayFunction the function to use to compute the delay before a next attempt
* @param exception the execution exception that is expected in order to trigger the delay
* @param exception type
* @throws NullPointerException if {@code delayFunction} or {@code exception} are null
*/
@SuppressWarnings("unchecked")
public S withDelayFnOn(ContextualSupplier delayFunction, Class exception) {
withDelayFn(delayFunction);
Assert.notNull(exception, "exception");
config.delayException = exception;
return (S) this;
}
/**
* Sets the {@code delayFunction} that computes the next delay before allowing another execution. Delays will only
* occur for results that equal the {@code result}.
*
* The {@code delayFunction} must complete quickly, not have side-effects, and always return the same result for the
* same input. Exceptions thrown by the {@code delayFunction} method will not be handled and will
* cause Failsafe's execution to abort.
*
*
* Notes:
*
*
A negative return value will cause Failsafe to use a configured fixed or backoff delay
*
Any configured jitter is still applied to DelayFunction provided values
*
Any configured max duration is still applied to DelayFunction provided values
*
The {@link ExecutionContext} that is provided to the {@code delayFunction} may be {@code null} if the prior execution
* exception was manually recorded outside of a Failsafe execution.
*
*
*
* @param delayFunction the function to use to compute the delay before a next attempt
* @param result the execution result that is expected in order to trigger the delay
* @throws NullPointerException if {@code delayFunction} or {@code result} are null
*/
@SuppressWarnings("unchecked")
public S withDelayFnWhen(ContextualSupplier delayFunction, R result) {
withDelayFn(delayFunction);
Assert.notNull(result, "result");
config.delayResult = result;
return (S) this;
}
}
failsafe-failsafe-parent-3.3.2/core/src/main/java/dev/failsafe/DelayablePolicyConfig.java 0000664 0000000 0000000 00000004637 14445610507 0031317 0 ustar 00root root 0000000 0000000 /*
* Copyright 2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License
*/
package dev.failsafe;
import dev.failsafe.function.ContextualSupplier;
import java.time.Duration;
/**
* Configuration for policies that can delay between executions.
*
* @param result type
* @author Jonathan Halterman
*/
public abstract class DelayablePolicyConfig extends FailurePolicyConfig {
Duration delay;
R delayResult;
Class extends Throwable> delayException;
ContextualSupplier delayFn;
protected DelayablePolicyConfig() {
}
protected DelayablePolicyConfig(DelayablePolicyConfig config) {
super(config);
delay = config.delay;
delayResult = config.delayResult;
delayException = config.delayException;
delayFn = config.delayFn;
}
/**
* Returns the delay until the next execution attempt can be performed.
*
* @see DelayablePolicyBuilder#withDelay(Duration)
*/
public Duration getDelay() {
return delay;
}
/**
* Returns the function that determines the next delay before another execution can be performed.
*
* @see DelayablePolicyBuilder#withDelayFn(ContextualSupplier)
* @see DelayablePolicyBuilder#withDelayFnOn(ContextualSupplier, Class)
* @see DelayablePolicyBuilder#withDelayFnWhen(ContextualSupplier, Object)
*/
public ContextualSupplier getDelayFn() {
return delayFn;
}
/**
* Returns the Throwable that must be matched in order to delay using the {@link #getDelayFn()}.
*
* @see DelayablePolicyBuilder#withDelayFnOn(ContextualSupplier, Class)
*/
public Class extends Throwable> getDelayException() {
return delayException;
}
/**
* Returns the result that must be matched in order to delay using the {@link #getDelayFn()}.
*
* @see DelayablePolicyBuilder#withDelayFnWhen(ContextualSupplier, Object)
*/
public R getDelayResult() {
return delayResult;
}
}
failsafe-failsafe-parent-3.3.2/core/src/main/java/dev/failsafe/Execution.java 0000664 0000000 0000000 00000006016 14445610507 0027063 0 ustar 00root root 0000000 0000000 /*
* Copyright 2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License
*/
package dev.failsafe;
import dev.failsafe.internal.util.Assert;
import dev.failsafe.internal.util.Lists;
import java.time.Duration;
/**
* Tracks synchronous executions and handles failures according to one or more {@link Policy policies}. Execution
* results must be explicitly recorded via one of the {@code record} methods.
*
* @param result type
* @author Jonathan Halterman
*/
public interface Execution extends ExecutionContext {
/**
* Creates a new {@code Execution} that will use the {@code outerPolicy} and {@code innerPolicies} to handle
* failures. Policies are applied in reverse order, with the last policy being applied first.
*
* @throws NullPointerException if {@code outerPolicy} is null
*/
@SafeVarargs
static Execution of(Policy outerPolicy, Policy... policies) {
return new SyncExecutionImpl<>(Lists.of(Assert.notNull(outerPolicy, "outerPolicy"), policies));
}
/**
* Records and completes the execution successfully.
*
* @throws IllegalStateException if the execution is already complete
*/
void complete();
/**
* Returns whether the execution is complete or if it can be retried. An execution is considered complete only when
* all configured policies consider the execution complete.
*/
boolean isComplete();
/**
* Returns the time to delay before the next execution attempt. Returns {@code 0} if an execution has not yet
* occurred.
*/
Duration getDelay();
/**
* Records an execution {@code result} or {@code exception} which triggers failure handling, if needed, by the
* configured policies. If policy handling is not possible or completed, the execution is completed.
*
* @throws IllegalStateException if the execution is already complete
*/
void record(R result, Throwable exception);
/**
* Records an execution {@code result} which triggers failure handling, if needed, by the configured policies. If
* policy handling is not possible or completed, the execution is completed.
*
* @throws IllegalStateException if the execution is already complete
*/
void recordResult(R result);
/**
* Records an {@code exception} which triggers failure handling, if needed, by the configured policies. If policy
* handling is not possible or completed, the execution is completed.
*
* @throws IllegalStateException if the execution is already complete
*/
void recordException(Throwable exception);
}
failsafe-failsafe-parent-3.3.2/core/src/main/java/dev/failsafe/ExecutionContext.java 0000664 0000000 0000000 00000005566 14445610507 0030441 0 ustar 00root root 0000000 0000000 /*
* Copyright 2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License
*/
package dev.failsafe;
import dev.failsafe.function.CheckedRunnable;
import java.time.Duration;
import java.time.Instant;
import java.util.concurrent.CompletableFuture;
/**
* Contextual execution information.
*
* @param result type
* @author Jonathan Halterman
*/
public interface ExecutionContext {
/**
* Sets the {@code cancelCallback} to be called if the execution is cancelled, such as by the resulting {@link Call}
* or {@link CompletableFuture}, or a {@link Timeout}. Any exception thrown by the {@code cancelCallback} is ignored.
*/
void onCancel(CheckedRunnable cancelCallback);
/**
* Returns the elapsed time since initial execution began.
*/
Duration getElapsedTime();
/**
* Returns the elapsed time since the last execution attempt began.
*/
Duration getElapsedAttemptTime();
/**
* Gets the number of execution attempts so far, including attempts that are blocked before being executed, such as
* when a {@link CircuitBreaker} is open. Will return {@code 0} when the first attempt is in progress or has yet to
* begin.
*/
int getAttemptCount();
/**
* Gets the number of completed executions so far. Executions that are blocked, such as when a {@link CircuitBreaker}
* is open, are not counted. Will return {@code 0} when the first attempt is in progress or has yet to begin.
*/
int getExecutionCount();
/**
* Returns the last exception that was recorded else {@code null}.
*/
T getLastException();
/**
* Returns the last result that was recorded else {@code null}.
*/
R getLastResult();
/**
* Returns the last result that was recorded else the {@code defaultValue}.
*/
R getLastResult(R defaultValue);
/**
* Returns the time that the initial execution started.
*/
Instant getStartTime();
/**
* Returns whether the execution has been cancelled. In this case the implementor should attempt to stop execution.
*/
boolean isCancelled();
/**
* Returns {@code true} when an execution result has not yet been recorded, meaning this is the first execution
* attempt.
*/
boolean isFirstAttempt();
/**
* Returns {@code true} when an execution result has already been recorded, meaning the execution is being retried.
*/
boolean isRetry();
}
failsafe-failsafe-parent-3.3.2/core/src/main/java/dev/failsafe/ExecutionImpl.java 0000664 0000000 0000000 00000017615 14445610507 0027714 0 ustar 00root root 0000000 0000000 /*
* Copyright 2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License
*/
package dev.failsafe;
import dev.failsafe.function.CheckedRunnable;
import dev.failsafe.internal.util.Assert;
import dev.failsafe.spi.ExecutionInternal;
import dev.failsafe.spi.ExecutionResult;
import dev.failsafe.spi.PolicyExecutor;
import java.time.Duration;
import java.time.Instant;
import java.util.ArrayList;
import java.util.List;
import java.util.ListIterator;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
/**
* Execution and ExecutionInternal implementation.
*
* @param result type
* @author Jonathan Halterman
*/
class ExecutionImpl implements ExecutionInternal {
// -- Cross-attempt state --
final List> policyExecutors;
// When the first execution attempt was started
private volatile Instant startTime;
// Number of execution attempts
private final AtomicInteger attempts;
// Number of completed executions
private final AtomicInteger executions;
// The latest execution attenpt
private final AtomicReference> latest;
// -- Per-attempt state --
// The result of the previous execution attempt
private final ExecutionResult previousResult;
// The result of the current execution attempt;
volatile ExecutionResult result;
// When the most recent execution attempt was started
private volatile Instant attemptStartTime;
// The index of a PolicyExecutor that cancelled the execution. Integer.MIN_VALUE represents non-cancelled.
volatile int cancelledIndex = Integer.MIN_VALUE;
// The user-provided callback to be called when an execution is cancelled
volatile CheckedRunnable cancelCallback;
// Whether the execution has pre-executed indicating it has started
private volatile boolean preExecuted;
// Whether the execution attempt has been recorded
volatile boolean attemptRecorded;
// Whether the execution has been completed for all polices
volatile boolean completed;
/**
* Creates a new execution for the {@code policies}.
*/
ExecutionImpl(List extends Policy> policies) {
policyExecutors = new ArrayList<>(policies.size());
attempts = new AtomicInteger();
executions = new AtomicInteger();
latest = new AtomicReference<>(this);
previousResult = null;
// Create policy executors
ListIterator extends Policy> policyIterator = policies.listIterator(policies.size());
for (int i = 0; policyIterator.hasPrevious(); i++) {
Policy policy = Assert.notNull(policyIterator.previous(), "policies");
PolicyExecutor policyExecutor = policy.toExecutor(i);
policyExecutors.add(policyExecutor);
}
}
/**
* Create an execution for a new attempt.
*/
ExecutionImpl(ExecutionImpl execution) {
policyExecutors = execution.policyExecutors;
startTime = execution.startTime;
attempts = execution.attempts;
executions = execution.executions;
latest = execution.latest;
latest.set(this);
previousResult = execution.result;
}
/** Used for testing purposes only */
ExecutionImpl(ExecutionResult previousResult) {
policyExecutors = null;
attempts = new AtomicInteger();
executions = new AtomicInteger();
latest = new AtomicReference<>(this);
this.previousResult = previousResult;
}
@Override
public ExecutionResult getResult() {
return result;
}
@Override
public void onCancel(CheckedRunnable cancelCallback) {
this.cancelCallback = cancelCallback;
}
@Override
public synchronized void preExecute() {
if (!preExecuted) {
attemptStartTime = Instant.now();
if (startTime == null)
startTime = attemptStartTime;
preExecuted = true;
}
}
@Override
public boolean isPreExecuted() {
return preExecuted;
}
@Override
public synchronized void recordAttempt() {
if (!attemptRecorded) {
attempts.incrementAndGet();
attemptRecorded = true;
}
}
@Override
public synchronized void record(ExecutionResult result) {
if (preExecuted && !attemptRecorded) {
recordAttempt();
executions.incrementAndGet();
this.result = result;
}
}
/**
* Externally called. Records an execution and performs post-execution handling for the {@code result} against all
* configured policy executors. Returns whether the result is complete for all policies.
*
* @throws IllegalStateException if the execution is already complete
*/
synchronized ExecutionResult postExecute(ExecutionResult result) {
Assert.state(!completed, "Execution has already been completed");
record(result);
boolean allComplete = true;
for (PolicyExecutor policyExecutor : policyExecutors) {
result = policyExecutor.postExecute(this, result);
allComplete = allComplete && result.isComplete();
}
completed = allComplete;
return result;
}
/** Called indirectly by users. */
@Override
public boolean cancel() {
boolean cancelled = isCancelled();
if (!cancelled) {
cancelledIndex = Integer.MAX_VALUE;
if (cancelCallback != null) {
try {
cancelCallback.run();
} catch (Throwable ignore) {
}
}
}
return !cancelled && !completed;
}
/** Called by policies. */
@Override
public void cancel(PolicyExecutor policyExecutor) {
cancelledIndex = policyExecutor.getPolicyIndex();
if (cancelCallback != null) {
try {
cancelCallback.run();
} catch (Throwable ignore) {
}
}
}
@Override
public boolean isCancelled() {
return cancelledIndex > Integer.MIN_VALUE;
}
@Override
public boolean isCancelled(PolicyExecutor policyExecutor) {
return cancelledIndex > policyExecutor.getPolicyIndex();
}
@Override
public Object getLock() {
return latest;
}
@Override
public ExecutionInternal getLatest() {
return latest.get();
}
@Override
public Duration getElapsedTime() {
return startTime == null ? Duration.ZERO : Duration.between(startTime, Instant.now());
}
@Override
public Duration getElapsedAttemptTime() {
return attemptStartTime == null ? Duration.ZERO : Duration.between(attemptStartTime, Instant.now());
}
@Override
public int getAttemptCount() {
return attempts.get();
}
@Override
public int getExecutionCount() {
return executions.get();
}
@Override
@SuppressWarnings("unchecked")
public T getLastException() {
ExecutionResult r = result != null ? result : previousResult;
return r == null ? null : (T) r.getException();
}
@Override
public R getLastResult() {
ExecutionResult r = result != null ? result : previousResult;
return r == null ? null : r.getResult();
}
@Override
public R getLastResult(R defaultValue) {
ExecutionResult r = result != null ? result : previousResult;
return r == null ? defaultValue : r.getResult();
}
@Override
public Instant getStartTime() {
return startTime;
}
@Override
public boolean isFirstAttempt() {
return attempts.get() == (!attemptRecorded ? 0 : 1);
}
@Override
public boolean isRetry() {
return attempts.get() > (!attemptRecorded ? 0 : 1);
}
@Override
public String toString() {
return "[" + "attempts=" + attempts + ", executions=" + executions + ", lastResult=" + getLastResult()
+ ", lastException=" + getLastException() + ']';
}
}
failsafe-failsafe-parent-3.3.2/core/src/main/java/dev/failsafe/Failsafe.java 0000664 0000000 0000000 00000010517 14445610507 0026633 0 ustar 00root root 0000000 0000000 /*
* Copyright 2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License
*/
package dev.failsafe;
import dev.failsafe.internal.util.Assert;
import dev.failsafe.internal.util.Lists;
import java.util.Collections;
import java.util.List;
/**
* Simple, sophisticated failure handling.
*
* @author Jonathan Halterman
*/
public class Failsafe {
/**
* Creates and returns a new {@link FailsafeExecutor} instance that will handle failures according to the given {@code
* outerPolicy} and {@code policies}. The policies are composed around an execution and will handle execution results
* in reverse, with the last policy being applied first. For example, consider:
*
*
* This means the {@code CircuitBreaker} is first to evaluate the {@code Supplier}'s result, then the {@code
* RetryPolicy}, then the {@code Fallback}. Each policy makes its own determination as to whether the result
* represents a failure. This allows different policies to be used for handling different types of failures.
*
* @param result type
* @param
policy type
* @throws NullPointerException if {@code outerPolicy} is null
*/
@SafeVarargs
public static > FailsafeExecutor with(P outerPolicy, P... policies) {
Assert.notNull(outerPolicy, "outerPolicy");
return new FailsafeExecutor<>(Lists.of(outerPolicy, policies));
}
/**
* Creates and returns a new {@link FailsafeExecutor} instance that will handle failures according to the given {@code
* policies}. The {@code policies} are composed around an execution and will handle execution results in reverse, with
* the last policy being applied first. For example, consider:
*
*
* This means the {@code CircuitBreaker} is first to evaluate the {@code Supplier}'s result, then the {@code
* RetryPolicy}, then the {@code Fallback}. Each policy makes its own determination as to whether the result
* represents a failure. This allows different policies to be used for handling different types of failures.
*
* @param result type
* @throws NullPointerException if {@code policies} is null
* @throws IllegalArgumentException if {@code policies} is empty
*/
public static FailsafeExecutor with(List extends Policy> policies) {
Assert.notNull(policies, "policies");
Assert.isTrue(!policies.isEmpty(), "At least one policy must be supplied");
return new FailsafeExecutor<>(policies);
}
/**
* Creates and returns a noop {@link FailsafeExecutor} instance that treats any exception as a failure for the
* purposes of calling event listeners, and provides no additional failure handling.
*
* @param result type
* @throws NullPointerException if {@code policies} is null
* @throws IllegalArgumentException if {@code policies} is empty
*/
public static FailsafeExecutor none() {
return new FailsafeExecutor<>(Collections.emptyList());
}
}
failsafe-failsafe-parent-3.3.2/core/src/main/java/dev/failsafe/FailsafeException.java 0000664 0000000 0000000 00000002055 14445610507 0030510 0 ustar 00root root 0000000 0000000 /*
* Copyright 2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License
*/
package dev.failsafe;
/**
* Thrown when a synchronous Failsafe execution fails with an {@link Exception}, wrapping the underlying exception. Use
* {@link Throwable#getCause()} to learn the cause of the failure.
*
* @author Jonathan Halterman
*/
public class FailsafeException extends RuntimeException {
private static final long serialVersionUID = 1L;
public FailsafeException() {
}
public FailsafeException(Throwable t) {
super(t);
}
}
failsafe-failsafe-parent-3.3.2/core/src/main/java/dev/failsafe/FailsafeExecutor.java 0000664 0000000 0000000 00000043641 14445610507 0030356 0 ustar 00root root 0000000 0000000 /*
* Copyright 2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License
*/
package dev.failsafe;
import dev.failsafe.event.EventListener;
import dev.failsafe.event.ExecutionCompletedEvent;
import dev.failsafe.function.*;
import dev.failsafe.internal.EventHandler;
import dev.failsafe.internal.util.Assert;
import dev.failsafe.spi.AsyncExecutionInternal;
import dev.failsafe.spi.ExecutionResult;
import dev.failsafe.spi.FailsafeFuture;
import dev.failsafe.spi.Scheduler;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;
import java.util.function.BiConsumer;
import java.util.function.Function;
import static dev.failsafe.Functions.*;
/**
*
* An executor that handles failures according to configured {@link FailurePolicyBuilder policies}. Can be created via
* {@link Failsafe#with(Policy, Policy[])} to support policy based execution failure handling, or {@link
* Failsafe#none()} to support execution with no failure handling.
*
* Async executions are run by default on the {@link ForkJoinPool#commonPool()}. Alternative executors can be configured
* via {@link #with(ScheduledExecutorService)} and similar methods. All async executions are cancellable and
* interruptable via the returned CompletableFuture, even those run by a {@link ForkJoinPool} or {@link
* CompletionStage}.
*
* @param result type
* @author Jonathan Halterman
*/
public class FailsafeExecutor {
private Scheduler scheduler = Scheduler.DEFAULT;
private Executor executor;
/** Policies sorted outermost first */
final List extends Policy> policies;
private volatile EventHandler completeHandler;
private volatile EventHandler failureHandler;
private volatile EventHandler successHandler;
/**
* @throws IllegalArgumentException if {@code policies} is empty
*/
FailsafeExecutor(List extends Policy> policies) {
this.policies = policies;
}
/**
* Returns the currently configured policies.
*
* @see #compose(Policy)
*/
public List extends Policy> getPolicies() {
return policies;
}
/**
* Returns a new {@code FailsafeExecutor} that composes the currently configured policies around the given {@code
* innerPolicy}. For example, consider:
*
*
* This means the {@code CircuitBreaker} is first to evaluate the {@code Supplier}'s result, then the {@code
* RetryPolicy}, then the {@code Fallback}. Each policy makes its own determination as to whether the result
* represents a failure. This allows different policies to be used for handling different types of failures.
*
* @throws NullPointerException if {@code innerPolicy} is null
* @see #getPolicies()
*/
public
> FailsafeExecutor compose(P innerPolicy) {
Assert.notNull(innerPolicy, "innerPolicy");
List> composed = new ArrayList<>(policies);
composed.add(innerPolicy);
return new FailsafeExecutor<>(composed);
}
/**
* Executes the {@code supplier} until a successful result is returned or the configured policies are exceeded.
*
* @throws NullPointerException if the {@code supplier} is null
* @throws FailsafeException if the execution fails with a checked Exception. {@link FailsafeException#getCause()} can
* be used to learn the underlying checked exception.
*/
public T get(CheckedSupplier supplier) {
return call(toCtxSupplier(supplier));
}
/**
* Executes the {@code supplier} until a successful result is returned or the configured policies are exceeded.
*
* @throws NullPointerException if the {@code supplier} is null
* @throws FailsafeException if the execution fails with a checked Exception. {@link FailsafeException#getCause()} can
* be used to learn the underlying checked exception.
*/
public T get(ContextualSupplier supplier) {
return call(Assert.notNull(supplier, "supplier"));
}
/**
* Returns a call that can execute the {@code runnable} until a successful result is returned or the configured
* policies are exceeded.
*
* @throws NullPointerException if the {@code runnable} is null
*/
public Call newCall(ContextualRunnable runnable) {
return callSync(toCtxSupplier(runnable));
}
/**
* Returns a call that can execute the {@code supplier} until a successful result is returned or the configured
* policies are exceeded.
*
* @throws NullPointerException if the {@code supplier} is null
*/
public Call newCall(ContextualSupplier supplier) {
return callSync(Assert.notNull(supplier, "supplier"));
}
/**
* Executes the {@code supplier} asynchronously until a successful result is returned or the configured policies are
* exceeded.
*
* @throws NullPointerException if the {@code supplier} is null
* @throws RejectedExecutionException if the {@code supplier} cannot be scheduled for execution
*/
public CompletableFuture getAsync(CheckedSupplier supplier) {
return callAsync(future -> getPromise(toCtxSupplier(supplier), executor), false);
}
/**
* Executes the {@code supplier} asynchronously until a successful result is returned or the configured policies are
* exceeded.
*
* @throws NullPointerException if the {@code supplier} is null
* @throws RejectedExecutionException if the {@code supplier} cannot be scheduled for execution
*/
public CompletableFuture getAsync(ContextualSupplier supplier) {
return callAsync(future -> getPromise(supplier, executor), false);
}
/**
* This method is intended for integration with asynchronous code.
*
* Executes the {@code runnable} asynchronously until a successful result is recorded or the configured policies are
* exceeded. Executions must be recorded via one of the {@code AsyncExecution.record} methods which will trigger
* failure handling, if needed, by the configured policies, else the resulting {@link CompletableFuture} will be
* completed. Any exception that is thrown from the {@code runnable} will automatically be recorded via {@link
* AsyncExecution#recordException(Throwable)}.
*
*
* @throws NullPointerException if the {@code runnable} is null
* @throws RejectedExecutionException if the {@code runnable} cannot be scheduled for execution
*/
public CompletableFuture getAsyncExecution(AsyncRunnable runnable) {
return callAsync(future -> getPromiseExecution(runnable, executor), true);
}
/**
* Executes the {@code supplier} asynchronously until the resulting future is successfully completed or the configured
* policies are exceeded.
*
Cancelling the resulting {@link CompletableFuture} will automatically cancels the supplied {@link
* CompletionStage} if it's a {@link Future}.
*
* @throws NullPointerException if the {@code supplier} is null
* @throws RejectedExecutionException if the {@code supplier} cannot be scheduled for execution
*/
public CompletableFuture getStageAsync(CheckedSupplier extends CompletionStage> supplier) {
return callAsync(future -> getPromiseOfStage(toCtxSupplier(supplier), future, executor), false);
}
/**
* Executes the {@code supplier} asynchronously until the resulting future is successfully completed or the configured
* policies are exceeded.
*
Cancelling the resulting {@link CompletableFuture} will automatically cancels the supplied {@link
* CompletionStage} if it's a {@link Future}.
*
* @throws NullPointerException if the {@code supplier} is null
* @throws RejectedExecutionException if the {@code supplier} cannot be scheduled for execution
*/
public CompletableFuture getStageAsync(
ContextualSupplier> supplier) {
return callAsync(future -> getPromiseOfStage(supplier, future, executor), false);
}
/**
* Executes the {@code runnable} until successful or until the configured policies are exceeded.
*
* @throws NullPointerException if the {@code runnable} is null
* @throws FailsafeException if the execution fails with a checked Exception. {@link FailsafeException#getCause()} can
* be used to learn the underlying checked exception.
*/
public void run(CheckedRunnable runnable) {
call(toCtxSupplier(runnable));
}
/**
* Executes the {@code runnable} until successful or until the configured policies are exceeded.
*
* @throws NullPointerException if the {@code runnable} is null
* @throws FailsafeException if the execution fails with a checked Exception. {@link FailsafeException#getCause()} can
* be used to learn the underlying checked exception.
*/
public void run(ContextualRunnable runnable) {
call(toCtxSupplier(runnable));
}
/**
* Executes the {@code runnable} asynchronously until successful or until the configured policies are exceeded.
*
* @throws NullPointerException if the {@code runnable} is null
* @throws RejectedExecutionException if the {@code runnable} cannot be scheduled for execution
*/
public CompletableFuture runAsync(CheckedRunnable runnable) {
return callAsync(future -> getPromise(toCtxSupplier(runnable), executor), false);
}
/**
* Executes the {@code runnable} asynchronously until successful or until the configured policies are exceeded.
*
* @throws NullPointerException if the {@code runnable} is null
* @throws RejectedExecutionException if the {@code runnable} cannot be scheduled for execution
*/
public CompletableFuture runAsync(ContextualRunnable runnable) {
return callAsync(future -> getPromise(toCtxSupplier(runnable), executor), false);
}
/**
* This method is intended for integration with asynchronous code.
*
* Executes the {@code runnable} asynchronously until a successful result is recorded or the configured policies are
* exceeded. Executions must be recorded via one of the {@code AsyncExecution.record} methods which will trigger
* failure handling, if needed, by the configured policies, else the resulting {@link CompletableFuture} will be
* completed. Any exception that is thrown from the {@code runnable} will automatically be recorded via {@link
* AsyncExecution#recordException(Throwable)}.
*
*
* @throws NullPointerException if the {@code runnable} is null
* @throws RejectedExecutionException if the {@code runnable} cannot be scheduled for execution
*/
public CompletableFuture runAsyncExecution(AsyncRunnable runnable) {
return callAsync(future -> getPromiseExecution(runnable, executor), true);
}
/**
* Registers the {@code listener} to be called when an execution is complete. This occurs when an execution is
* successful according to all policies, or all policies have been exceeded.
*
Note: Any exceptions that are thrown from within the {@code listener} are ignored.
*/
public FailsafeExecutor onComplete(EventListener> listener) {
completeHandler = EventHandler.ofExecutionCompleted(Assert.notNull(listener, "listener"));
return this;
}
/**
* Registers the {@code listener} to be called when an execution fails. This occurs when the execution fails according
* to some policy, and all policies have been exceeded.
*
Note: Any exceptions that are thrown from within the {@code listener} are ignored. To provide an alternative
* result for a failed execution, use a {@link Fallback}.
*/
public FailsafeExecutor onFailure(EventListener> listener) {
failureHandler = EventHandler.ofExecutionCompleted(Assert.notNull(listener, "listener"));
return this;
}
/**
* Registers the {@code listener} to be called when an execution is successful. If multiple policies, are configured,
* this handler is called when execution is complete and all policies succeed. If all policies do not
* succeed, then the {@link #onFailure(EventListener)} registered listener is called instead.
*
Note: Any exceptions that are thrown from within the {@code listener} are ignored.
*/
public FailsafeExecutor onSuccess(EventListener> listener) {
successHandler = EventHandler.ofExecutionCompleted(Assert.notNull(listener, "listener"));
return this;
}
/**
* Configures the {@code scheduledExecutorService} to use for performing asynchronous executions and listener
* callbacks.
*
* Note: The {@code scheduledExecutorService} should have a core pool size of at least 2 in order for {@link Timeout
* timeouts} to work.
*
*
* @throws NullPointerException if {@code scheduledExecutorService} is null
* @throws IllegalArgumentException if the {@code scheduledExecutorService} has a core pool size of less than 2
*/
public FailsafeExecutor with(ScheduledExecutorService scheduledExecutorService) {
this.scheduler = Scheduler.of(Assert.notNull(scheduledExecutorService, "scheduledExecutorService"));
return this;
}
/**
* Configures the {@code executorService} to use for performing asynchronous executions and listener callbacks. For
* async executions that require a delay, an internal ScheduledExecutorService will be used for the delay, then the
* {@code executorService} will be used for actual execution.
*
* Note: The {@code executorService} should have a core pool size or parallelism of at least 2 in order for {@link
* Timeout timeouts} to work.
*
*
* @throws NullPointerException if {@code executorService} is null
*/
public FailsafeExecutor with(ExecutorService executorService) {
this.scheduler = Scheduler.of(Assert.notNull(executorService, "executorService"));
return this;
}
/**
* Configures the {@code executor} to use as a wrapper around executions. If the {@code executor} is actually an
* instance of {@link ExecutorService}, then the {@code executor} will be configured via {@link
* #with(ExecutorService)} instead.
*
* The {@code executor} is responsible for propagating executions. Executions that normally return a result, such as
* {@link #get(CheckedSupplier)} will return {@code null} since the {@link Executor} interface does not support
* results.
*
*
The {@code executor} will not be used for {@link #getStageAsync(CheckedSupplier) getStageAsync} calls since
* those require a returned result.
*
*
* @throws NullPointerException if {@code executor} is null
*/
public FailsafeExecutor with(Executor executor) {
Assert.notNull(executor, "executor");
if (executor instanceof ExecutorService)
with((ExecutorService) executor);
else
this.executor = executor;
return this;
}
/**
* Configures the {@code scheduler} to use for performing asynchronous executions and listener callbacks.
*
* @throws NullPointerException if {@code scheduler} is null
*/
public FailsafeExecutor with(Scheduler scheduler) {
this.scheduler = Assert.notNull(scheduler, "scheduler");
return this;
}
/**
* Calls the {@code innerSupplier} synchronously, handling results according to the configured policies.
*/
@SuppressWarnings({ "unchecked", "rawtypes" })
private T call(ContextualSupplier innerSupplier) {
SyncExecutionImpl execution = new SyncExecutionImpl(this, scheduler, null,
Functions.get(innerSupplier, executor));
return execution.executeSync();
}
/**
* Returns a Call that calls the {@code innerSupplier} synchronously, handling results according to the configured
* policies.
*/
@SuppressWarnings({ "unchecked", "rawtypes" })
private Call callSync(ContextualSupplier innerSupplier) {
CallImpl call = new CallImpl<>();
new SyncExecutionImpl(this, scheduler, call, Functions.get(innerSupplier, executor));
return call;
}
/**
* Calls the asynchronous {@code innerFn} via the configured Scheduler, handling results according to the configured
* policies.
*
* @param asyncExecution whether this is a detached, async execution that must be manually completed
* @throws NullPointerException if the {@code innerFn} is null
* @throws RejectedExecutionException if the {@code innerFn} cannot be scheduled for execution
*/
@SuppressWarnings({ "unchecked", "rawtypes" })
private CompletableFuture callAsync(
Function, Function, CompletableFuture>>> innerFn,
boolean asyncExecution) {
FailsafeFuture future = new FailsafeFuture(completionHandler);
AsyncExecutionImpl execution = new AsyncExecutionImpl(policies, scheduler, future, asyncExecution,
innerFn.apply(future));
future.setExecution(execution);
execution.executeAsync();
return future;
}
final BiConsumer, ExecutionContext> completionHandler = (result, context) -> {
if (successHandler != null && result.getSuccessAll())
successHandler.handle(result, context);
else if (failureHandler != null && !result.getSuccessAll())
failureHandler.handle(result, context);
if (completeHandler != null)
completeHandler.handle(result, context);
};
} failsafe-failsafe-parent-3.3.2/core/src/main/java/dev/failsafe/FailurePolicyBuilder.java 0000664 0000000 0000000 00000016612 14445610507 0031201 0 ustar 00root root 0000000 0000000 /*
* Copyright 2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License
*/
package dev.failsafe;
import dev.failsafe.function.CheckedBiPredicate;
import dev.failsafe.function.CheckedPredicate;
import dev.failsafe.internal.util.Assert;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
/**
* A Policy that allows configurable conditions to determine whether an execution is a failure.
*
*
By default, any exception is considered a failure and will be handled by the policy. You can override this by
* specifying your own {@code handle} conditions. The default exception handling condition will only be overridden by
* another condition that handles failure exceptions such as {@link #handle(Class)} or {@link #handleIf(CheckedBiPredicate)}.
* Specifying a condition that only handles results, such as {@link #handleResult(Object)} or
* {@link #handleResultIf(CheckedPredicate)} will not replace the default exception handling condition.
*
If multiple {@code handle} conditions are specified, any condition that matches an execution result or exception
* will trigger policy handling.
*
*
* @param self type
* @param config type
* @param result type
* @author Jonathan Halterman
*/
@SuppressWarnings("unchecked")
public abstract class FailurePolicyBuilder, R> extends PolicyBuilder {
protected FailurePolicyBuilder(C config) {
super(config);
}
/**
* Specifies the exception to handle as a failure. Any exception that is assignable from the {@code exception} will be
* handled.
*
* @throws NullPointerException if {@code exception} is null
*/
public S handle(Class extends Throwable> exception) {
Assert.notNull(exception, "exception");
return handle(Arrays.asList(exception));
}
/**
* Specifies the exceptions to handle as failures. Any exceptions that are assignable from the {@code exceptions} will
* be handled.
*
* @throws NullPointerException if {@code exceptions} is null
* @throws IllegalArgumentException if exceptions is empty
*/
@SafeVarargs
public final S handle(Class extends Throwable>... exceptions) {
Assert.notNull(exceptions, "exceptions");
Assert.isTrue(exceptions.length > 0, "exceptions cannot be empty");
return handle(Arrays.asList(exceptions));
}
/**
* Specifies the exceptions to handle as failures. Any exceptions that are assignable from the {@code exceptions} will
* be handled.
*
* @throws NullPointerException if {@code exceptions} is null
* @throws IllegalArgumentException if exceptions is null or empty
*/
public S handle(List> exceptions) {
Assert.notNull(exceptions, "exceptions");
Assert.isTrue(!exceptions.isEmpty(), "exceptions cannot be empty");
config.exceptionsChecked = true;
config.failureConditions.add(failurePredicateFor(exceptions));
return (S) this;
}
/**
* Specifies that a failure has occurred if the {@code failurePredicate} matches the exception. Any exception thrown
* from the {@code failurePredicate} is treated as a {@code false} result.
*
* @throws NullPointerException if {@code failurePredicate} is null
*/
public S handleIf(CheckedPredicate extends Throwable> failurePredicate) {
Assert.notNull(failurePredicate, "failurePredicate");
config.exceptionsChecked = true;
config.failureConditions.add(failurePredicateFor(failurePredicate));
return (S) this;
}
/**
* Specifies that a failure has occurred if the {@code resultPredicate} matches the execution result. Any exception
* thrown from the {@code resultPredicate} is treated as a {@code false} result.
*
* @throws NullPointerException if {@code resultPredicate} is null
*/
@SuppressWarnings("unchecked")
public S handleIf(CheckedBiPredicate resultPredicate) {
Assert.notNull(resultPredicate, "resultPredicate");
config.exceptionsChecked = true;
config.failureConditions.add((CheckedBiPredicate) resultPredicate);
return (S) this;
}
/**
* Specifies that a failure has occurred if the {@code result} matches the execution result. This method is only
* considered when a result is returned from an execution, not when an exception is thrown.
*/
public S handleResult(R result) {
config.failureConditions.add(resultPredicateFor(result));
return (S) this;
}
/**
* Specifies that a failure has occurred if the {@code resultPredicate} matches the execution result. This method is
* only considered when a result is returned from an execution, not when an exception is thrown. To handle results or
* exceptions with the same condition, use {@link #handleIf(CheckedBiPredicate)}. Any exception thrown from the {@code
* resultPredicate} is treated as a {@code false} result.
*
* @throws NullPointerException if {@code resultPredicate} is null
*/
public S handleResultIf(CheckedPredicate resultPredicate) {
Assert.notNull(resultPredicate, "resultPredicate");
config.failureConditions.add(resultPredicateFor(resultPredicate));
return (S) this;
}
/**
* Returns a predicate that evaluates whether the {@code result} equals an execution result.
*/
static CheckedBiPredicate resultPredicateFor(R result) {
return (t, u) -> result == null ? t == null && u == null : Objects.equals(result, t);
}
/**
* Returns a predicate that evaluates the {@code failurePredicate} against a failure.
*/
@SuppressWarnings("unchecked")
static CheckedBiPredicate failurePredicateFor(
CheckedPredicate extends Throwable> failurePredicate) {
return (t, u) -> u != null && ((CheckedPredicate) failurePredicate).test(u);
}
/**
* Returns a predicate that evaluates the {@code resultPredicate} against a result, when present.
*
* Short-circuits to false without invoking {@code resultPredicate}, when result is not present (i.e.
* BiPredicate.test(null, Throwable)).
*/
static CheckedBiPredicate resultPredicateFor(CheckedPredicate resultPredicate) {
return (t, u) -> {
if (u == null) {
return resultPredicate.test(t);
} else {
// resultPredicate is only defined over the success type.
// It doesn't know how to handle a failure of type Throwable,
// so we return false here.
return false;
}
};
}
/**
* Returns a predicate that returns whether any of the {@code failures} are assignable from an execution failure.
*/
static CheckedBiPredicate failurePredicateFor(List> failures) {
return (t, u) -> {
if (u == null)
return false;
for (Class extends Throwable> failureType : failures)
if (failureType.isAssignableFrom(u.getClass()))
return true;
return false;
};
}
}
failsafe-failsafe-parent-3.3.2/core/src/main/java/dev/failsafe/FailurePolicyConfig.java 0000664 0000000 0000000 00000004316 14445610507 0031016 0 ustar 00root root 0000000 0000000 /*
* Copyright 2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License
*/
package dev.failsafe;
import dev.failsafe.function.CheckedBiPredicate;
import dev.failsafe.function.CheckedPredicate;
import java.util.ArrayList;
import java.util.List;
/**
* Configuration for policies that handle specific failures and conditions.
*
* @param result type
* @author Jonathan Halterman
*/
public abstract class FailurePolicyConfig extends PolicyConfig {
/** Indicates whether exceptions are checked by a configured failure condition */
boolean exceptionsChecked;
/** Conditions that determine whether an execution is a failure */
List> failureConditions;
protected FailurePolicyConfig() {
failureConditions = new ArrayList<>();
}
protected FailurePolicyConfig(FailurePolicyConfig config) {
super(config);
exceptionsChecked = config.exceptionsChecked;
failureConditions = new ArrayList<>(config.failureConditions);
}
/**
* Returns whether exceptions are checked by a configured failure condition.
*/
public boolean isExceptionsChecked() {
return exceptionsChecked;
}
/**
* Returns the conditions under which a result or Throwable should be treated as a failure and handled.
*
* @see FailurePolicyBuilder#handle(Class...)
* @see FailurePolicyBuilder#handle(List)
* @see FailurePolicyBuilder#handleIf(CheckedBiPredicate)
* @see FailurePolicyBuilder#handleIf(CheckedPredicate)
* @see FailurePolicyBuilder#handleResult(Object)
* @see FailurePolicyBuilder#handleResultIf(CheckedPredicate)
*/
public List> getFailureConditions() {
return failureConditions;
}
}
failsafe-failsafe-parent-3.3.2/core/src/main/java/dev/failsafe/Fallback.java 0000664 0000000 0000000 00000020434 14445610507 0026617 0 ustar 00root root 0000000 0000000 /*
* Copyright 2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License
*/
package dev.failsafe;
import dev.failsafe.function.CheckedConsumer;
import dev.failsafe.function.CheckedRunnable;
import dev.failsafe.function.CheckedSupplier;
import dev.failsafe.event.ExecutionAttemptedEvent;
import dev.failsafe.function.CheckedFunction;
import dev.failsafe.internal.FallbackImpl;
import dev.failsafe.internal.util.Assert;
import java.util.concurrent.CompletionStage;
import static dev.failsafe.Functions.toFn;
/**
* A Policy that handles failures using a fallback function or result.
*
* This class is threadsafe.
*
*
* @param result type
* @author Jonathan Halterman
* @see TimeoutConfig
* @see FallbackBuilder
*/
public interface Fallback extends Policy {
/**
* Creates a new FallbackBuilder that will be based on the {@code config}.
*/
static FallbackBuilder builder(FallbackConfig config) {
return new FallbackBuilder<>(config);
}
/**
* Returns the {@code fallback} to be executed if execution fails.
*
* @throws NullPointerException if {@code fallback} is null
*/
static FallbackBuilder builder(CheckedRunnable fallback) {
return new FallbackBuilder<>(toFn(Assert.notNull(fallback, "fallback")), null);
}
/**
* Returns the {@code fallback} to be executed if execution fails.
*
* @throws NullPointerException if {@code fallback} is null
*/
static FallbackBuilder builder(CheckedSupplier extends R> fallback) {
return new FallbackBuilder<>(toFn(Assert.notNull(fallback, "fallback")), null);
}
/**
* Returns the {@code fallback} to be executed if execution fails. The {@code fallback} accepts an {@link
* ExecutionAttemptedEvent}.
*
* @throws NullPointerException if {@code fallback} is null
*/
@SuppressWarnings({ "unchecked", "rawtypes" })
static FallbackBuilder builder(CheckedConsumer> fallback) {
return new FallbackBuilder<>(toFn(Assert.notNull((CheckedConsumer) fallback, "fallback")), null);
}
/**
* Returns the {@code fallback} to be executed if execution fails. The {@code fallback} applies an {@link
* ExecutionAttemptedEvent}.
*
* @throws NullPointerException if {@code fallback} is null
*/
@SuppressWarnings({ "unchecked", "rawtypes" })
static FallbackBuilder builder(CheckedFunction, ? extends R> fallback) {
return new FallbackBuilder<>(Assert.notNull((CheckedFunction) fallback, "fallback"), null);
}
/**
* Returns the {@code fallbackResult} to be provided if execution fails.
*/
static FallbackBuilder builder(R fallbackResult) {
return new FallbackBuilder<>(toFn(fallbackResult), null);
}
/**
* Returns the {@code fallback} to be executed if execution fails and allows an alternative exception to be supplied
* instead. The {@code fallback} applies an {@link ExecutionAttemptedEvent} and must return an exception.
*
* @throws NullPointerException if {@code fallback} is null
*/
static FallbackBuilder builderOfException(
CheckedFunction, ? extends Exception> fallback) {
Assert.notNull(fallback, "fallback");
return new FallbackBuilder<>(e -> {
throw fallback.apply(e);
}, null);
}
/**
* Returns the {@code fallback} to be executed if execution fails.
*
* @throws NullPointerException if {@code fallback} is null
*/
@SuppressWarnings({ "unchecked", "rawtypes" })
static FallbackBuilder builderOfStage(CheckedSupplier extends CompletionStage> fallback) {
return new FallbackBuilder<>(null, (CheckedFunction) toFn(Assert.notNull(fallback, "fallback")));
}
/**
* Returns the {@code fallback} to be executed if execution fails. The {@code fallback} accepts an {@link
* ExecutionAttemptedEvent}.
*
* @throws NullPointerException if {@code fallback} is null
*/
@SuppressWarnings({ "unchecked", "rawtypes" })
static FallbackBuilder builderOfStage(
CheckedFunction, ? extends CompletionStage> fallback) {
return new FallbackBuilder<>(null, Assert.notNull((CheckedFunction) fallback, "fallback"));
}
/**
* Returns the {@code fallback} to be executed if execution fails.
*
* @throws NullPointerException if {@code fallback} is null
*/
static Fallback of(CheckedRunnable fallback) {
return new FallbackImpl<>(new FallbackConfig<>(toFn(Assert.notNull(fallback, "fallback")), null));
}
/**
* Returns the {@code fallback} to be executed if execution fails.
*
* @throws NullPointerException if {@code fallback} is null
*/
static Fallback of(CheckedSupplier extends R> fallback) {
return new FallbackImpl<>(new FallbackConfig<>(toFn(Assert.notNull(fallback, "fallback")), null));
}
/**
* Returns the {@code fallback} to be executed if execution fails. The {@code fallback} accepts an {@link
* ExecutionAttemptedEvent}.
*
* @throws NullPointerException if {@code fallback} is null
*/
@SuppressWarnings({ "unchecked", "rawtypes" })
static Fallback of(CheckedConsumer> fallback) {
return new FallbackImpl<>(new FallbackConfig<>(toFn(Assert.notNull((CheckedConsumer) fallback, "fallback")), null));
}
/**
* Returns the {@code fallback} to be executed if execution fails. The {@code fallback} applies an {@link
* ExecutionAttemptedEvent}.
*
* @throws NullPointerException if {@code fallback} is null
*/
@SuppressWarnings({ "unchecked", "rawtypes" })
static Fallback of(CheckedFunction, ? extends R> fallback) {
return new FallbackImpl<>(new FallbackConfig<>(Assert.notNull((CheckedFunction) fallback, "fallback"), null));
}
/**
* Returns the {@code fallback} to be executed if execution fails and allows an alternative exception to be supplied
* instead. The {@code fallback} applies an {@link ExecutionAttemptedEvent} and must return an exception.
*
* @throws NullPointerException if {@code fallback} is null
*/
static Fallback ofException(
CheckedFunction, ? extends Exception> fallback) {
Assert.notNull(fallback, "fallback");
return new FallbackImpl<>(new FallbackConfig<>(e -> {
throw fallback.apply(e);
}, null));
}
/**
* Returns the {@code fallbackResult} to be provided if execution fails.
*/
static Fallback of(R fallbackResult) {
return new FallbackImpl<>(new FallbackConfig<>(toFn(fallbackResult), null));
}
/**
* Returns the {@code fallback} to be executed if execution fails.
*
* @throws NullPointerException if {@code fallback} is null
*/
@SuppressWarnings({ "unchecked", "rawtypes" })
static Fallback ofStage(CheckedSupplier extends CompletionStage> fallback) {
return new FallbackImpl<>(new FallbackConfig<>(null, (CheckedFunction) toFn(Assert.notNull(fallback, "fallback"))));
}
/**
* Returns the {@code fallback} to be executed if execution fails. The {@code fallback} accepts an {@link
* ExecutionAttemptedEvent}.
*
* @throws NullPointerException if {@code fallback} is null
*/
@SuppressWarnings({ "unchecked", "rawtypes" })
static Fallback ofStage(
CheckedFunction, ? extends CompletionStage> fallback) {
return new FallbackImpl<>(new FallbackConfig<>(null, Assert.notNull((CheckedFunction) fallback, "fallback")));
}
/**
* Returns a fallback that will return a null if execution fails.
*/
static Fallback none() {
return FallbackImpl.NONE;
}
/**
* Returns the {@link FallbackConfig} that the Fallback was built with.
*/
@Override
FallbackConfig getConfig();
}
failsafe-failsafe-parent-3.3.2/core/src/main/java/dev/failsafe/FallbackBuilder.java 0000664 0000000 0000000 00000006707 14445610507 0030135 0 ustar 00root root 0000000 0000000 /*
* Copyright 2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License
*/
package dev.failsafe;
import dev.failsafe.event.EventListener;
import dev.failsafe.event.ExecutionAttemptedEvent;
import dev.failsafe.function.CheckedBiPredicate;
import dev.failsafe.function.CheckedFunction;
import dev.failsafe.function.CheckedPredicate;
import dev.failsafe.internal.FallbackImpl;
import dev.failsafe.internal.util.Assert;
import java.util.concurrent.CompletableFuture;
/**
* Builds {@link Fallback} instances.
*
*
By default, any exception is considered a failure and will be handled by the policy. You can override this by
* specifying your own {@code handle} conditions. The default exception handling condition will only be overridden by
* another condition that handles failure exceptions such as {@link #handle(Class)} or {@link #handleIf(CheckedBiPredicate)}.
* Specifying a condition that only handles results, such as {@link #handleResult(Object)} or
* {@link #handleResultIf(CheckedPredicate)} will not replace the default exception handling condition.
*
If multiple {@code handle} conditions are specified, any condition that matches an execution result or failure
* will trigger policy handling.
*
*
* Note:
*
*
This class extends {@link FailurePolicyBuilder} which offers additional configuration.
*
This class is not threadsafe.
*
*
*
* @param result type
* @author Jonathan Halterman
* @see FallbackConfig
*/
public class FallbackBuilder extends FailurePolicyBuilder, FallbackConfig, R>
implements PolicyListeners, R> {
FallbackBuilder(CheckedFunction, R> fallback,
CheckedFunction, CompletableFuture> fallbackStage) {
super(new FallbackConfig<>());
config.fallback = fallback;
config.fallbackStage = fallbackStage;
}
FallbackBuilder(FallbackConfig config) {
super(new FallbackConfig<>(config));
}
/**
* Builds a new {@link Fallback} using the builder's configuration.
*/
public Fallback build() {
return new FallbackImpl<>(new FallbackConfig<>(config));
}
/**
* Registers the {@code listener} to be called when the last execution attempt prior to the fallback failed. You can
* also use {@link #onFailure(EventListener) onFailure} to determine when the fallback attempt also fails.
*
Note: Any exceptions that are thrown from within the {@code listener} are ignored.
*
* @throws NullPointerException if {@code listener} is null
*/
public FallbackBuilder onFailedAttempt(EventListener> listener) {
config.failedAttemptListener = Assert.notNull(listener, "listener");
return this;
}
/**
* Configures the fallback to run asynchronously.
*/
public FallbackBuilder withAsync() {
config.async = true;
return this;
}
}
failsafe-failsafe-parent-3.3.2/core/src/main/java/dev/failsafe/FallbackConfig.java 0000664 0000000 0000000 00000006747 14445610507 0027760 0 ustar 00root root 0000000 0000000 /*
* Copyright 2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License
*/
package dev.failsafe;
import dev.failsafe.event.EventListener;
import dev.failsafe.event.ExecutionAttemptedEvent;
import dev.failsafe.function.CheckedConsumer;
import dev.failsafe.function.CheckedFunction;
import dev.failsafe.function.CheckedRunnable;
import dev.failsafe.function.CheckedSupplier;
import java.util.concurrent.CompletableFuture;
/**
* Configuration for a {@link Fallback}.
*
* This class is threadsafe.
*
*
* @param result type
* @author Jonathan Halterman
* @see FallbackBuilder
*/
public class FallbackConfig extends FailurePolicyConfig {
CheckedFunction, R> fallback;
CheckedFunction, CompletableFuture> fallbackStage;
boolean async;
// Listeners
EventListener> failedAttemptListener;
FallbackConfig() {
}
FallbackConfig(FallbackConfig config) {
super(config);
fallback = config.fallback;
fallbackStage = config.fallbackStage;
async = config.async;
failedAttemptListener = config.failedAttemptListener;
}
FallbackConfig(CheckedFunction, R> fallback,
CheckedFunction, CompletableFuture> fallbackStage) {
this.fallback = fallback;
this.fallbackStage = fallbackStage;
}
/**
* Returns the fallback function, else {@code null} if a fallback stage function was configured instead.
*
* @see Fallback#of(CheckedRunnable)
* @see Fallback#of(CheckedSupplier)
* @see Fallback#of(CheckedConsumer)
* @see Fallback#of(CheckedFunction)
* @see Fallback#of(Object)
* @see Fallback#ofException(CheckedFunction)
* @see Fallback#builder(CheckedRunnable)
* @see Fallback#builder(CheckedSupplier)
* @see Fallback#builder(CheckedConsumer)
* @see Fallback#builder(CheckedFunction)
* @see Fallback#builder(Object)
* @see Fallback#builderOfException(CheckedFunction)
*/
public CheckedFunction, R> getFallback() {
return fallback;
}
/**
* Returns the fallback stage function, else {@code null} if a fallback function was configured instead.
*
* @see Fallback#ofStage(CheckedSupplier)
* @see Fallback#ofStage(CheckedFunction)
* @see Fallback#builderOfStage(CheckedSupplier)
* @see Fallback#builderOfStage(CheckedFunction)
*/
public CheckedFunction, CompletableFuture> getFallbackStage() {
return fallbackStage;
}
/**
* Returns whether the Fallback is configured to handle execution results asynchronously, separate from execution.
*
* @see FallbackBuilder#withAsync()
*/
public boolean isAsync() {
return async;
}
/**
* Returns the failed attempt event listener.
*
* @see FallbackBuilder#onFailedAttempt(EventListener)
*/
public EventListener> getFailedAttemptListener() {
return failedAttemptListener;
}
}
failsafe-failsafe-parent-3.3.2/core/src/main/java/dev/failsafe/Functions.java 0000664 0000000 0000000 00000023671 14445610507 0027076 0 ustar 00root root 0000000 0000000 /*
* Copyright 2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License
*/
package dev.failsafe;
import dev.failsafe.function.*;
import dev.failsafe.internal.util.Assert;
import dev.failsafe.spi.*;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Function;
/**
* Utilities for creating and applying Failsafe executable functions.
*
* @author Jonathan Halterman
*/
final class Functions {
/**
* Returns a Supplier for synchronous executions that pre-executes the {@code execution}, applies the {@code
* supplier}, records the result and returns the result. This implementation also handles Thread interrupts.
*
* @param result type
*/
static Function, ExecutionResult> get(ContextualSupplier supplier,
Executor executor) {
return execution -> {
ExecutionResult result;
Throwable throwable = null;
try {
execution.preExecute();
result = ExecutionResult.success(withExecutor(supplier, executor).get(execution));
} catch (Throwable t) {
throwable = t;
result = ExecutionResult.exception(t);
}
execution.record(result);
// Guard against race with Timeout interrupting the execution
synchronized (execution.getLock()) {
execution.setInterruptable(false);
if (execution.isInterrupted()) {
// Clear interrupt flag if interruption was performed by Failsafe
Thread.interrupted();
return execution.getResult();
} else if (throwable instanceof InterruptedException)
// Set interrupt flag if interruption was not performed by Failsafe
Thread.currentThread().interrupt();
}
return result;
};
}
/**
* Returns a Function for asynchronous executions that pre-executes the {@code execution}, applies the {@code
* supplier}, records the result and returns a promise containing the result.
*
* @param result type
*/
static Function, CompletableFuture>> getPromise(
ContextualSupplier supplier, Executor executor) {
Assert.notNull(supplier, "supplier");
return execution -> {
ExecutionResult result;
try {
execution.preExecute();
result = ExecutionResult.success(withExecutor(supplier, executor).get(execution));
} catch (Throwable t) {
result = ExecutionResult.exception(t);
}
execution.record(result);
return CompletableFuture.completedFuture(result);
};
}
/**
* Returns a Function for asynchronous executions that pre-executes the {@code execution}, runs the {@code runnable},
* and attempts to complete the {@code execution} if a failure occurs. Locks to ensure the resulting supplier cannot
* be applied multiple times concurrently.
*
* @param result type
*/
static Function, CompletableFuture>> getPromiseExecution(
AsyncRunnable runnable, Executor executor) {
Assert.notNull(runnable, "runnable");
return new Function, CompletableFuture>>() {
@Override
public synchronized CompletableFuture> apply(AsyncExecutionInternal execution) {
try {
execution.preExecute();
withExecutor(runnable, executor).run(execution);
} catch (Throwable e) {
execution.record(null, e);
}
// Result will be provided later via AsyncExecution.record
return ExecutionResult.nullFuture();
}
};
}
/**
* Returns a Function that for asynchronous executions that pre-executes the {@code execution}, applies the {@code
* supplier}, records the result and returns a promise containing the result.
*
* @param result type
* @throws UnsupportedOperationException when using
*/
@SuppressWarnings("unchecked")
static Function, CompletableFuture>> getPromiseOfStage(
ContextualSupplier> supplier, FailsafeFuture future,
Executor executor) {
Assert.notNull(supplier, "supplier");
return execution -> {
CompletableFuture> promise = new CompletableFuture<>();
try {
execution.preExecute();
CompletionStage extends R> stage = withExecutor(supplier, executor).get(execution);
if (stage == null) {
ExecutionResult r = ExecutionResult.success(null);
execution.record(r);
promise.complete(r);
} else {
// Propagate outer cancellations to the stage
if (stage instanceof Future)
future.propagateCancellation((Future) stage);
stage.whenComplete((result, exception) -> {
if (exception instanceof CompletionException)
exception = exception.getCause();
ExecutionResult r = exception == null ? ExecutionResult.success(result) : ExecutionResult.exception(exception);
execution.record(r);
promise.complete(r);
});
}
} catch (Throwable t) {
ExecutionResult result = ExecutionResult.exception(t);
execution.record(result);
promise.complete(result);
}
return promise;
};
}
/**
* Returns a Function that returns an execution result if one was previously recorded, else applies the {@code
* innerFn}.
*
* @param result type
*/
static Function, CompletableFuture>> toExecutionAware(
Function, CompletableFuture>> innerFn) {
return execution -> {
ExecutionResult result = execution.getResult();
if (result == null) {
return innerFn.apply(execution);
} else {
return CompletableFuture.completedFuture(result);
}
};
}
/**
* Returns a Function that asynchronously applies the {@code innerFn} on the first call, synchronously on subsequent
* calls, and returns a promise containing the result.
*
* @param result type
*/
static Function, CompletableFuture>> toAsync(
Function, CompletableFuture>> innerFn, Scheduler scheduler,
FailsafeFuture future) {
AtomicBoolean scheduled = new AtomicBoolean();
return execution -> {
if (scheduled.get()) {
return innerFn.apply(execution);
} else {
CompletableFuture> promise = new CompletableFuture<>();
Callable