├── .github
└── workflows
│ └── maven.yml
├── .gitignore
├── CHANGELOG.md
├── CONTRIBUTING.md
├── LICENSE
├── README.md
├── VERSIONING.md
├── bin
└── push-javadoc.sh
├── core
├── pom.xml
└── src
│ ├── main
│ ├── java
│ │ └── dev
│ │ │ └── failsafe
│ │ │ ├── AsyncExecution.java
│ │ │ ├── AsyncExecutionImpl.java
│ │ │ ├── Bulkhead.java
│ │ │ ├── BulkheadBuilder.java
│ │ │ ├── BulkheadConfig.java
│ │ │ ├── BulkheadFullException.java
│ │ │ ├── Call.java
│ │ │ ├── CallImpl.java
│ │ │ ├── CircuitBreaker.java
│ │ │ ├── CircuitBreakerBuilder.java
│ │ │ ├── CircuitBreakerConfig.java
│ │ │ ├── CircuitBreakerOpenException.java
│ │ │ ├── DelayablePolicyBuilder.java
│ │ │ ├── DelayablePolicyConfig.java
│ │ │ ├── Execution.java
│ │ │ ├── ExecutionContext.java
│ │ │ ├── ExecutionImpl.java
│ │ │ ├── Failsafe.java
│ │ │ ├── FailsafeException.java
│ │ │ ├── FailsafeExecutor.java
│ │ │ ├── FailurePolicyBuilder.java
│ │ │ ├── FailurePolicyConfig.java
│ │ │ ├── Fallback.java
│ │ │ ├── FallbackBuilder.java
│ │ │ ├── FallbackConfig.java
│ │ │ ├── Functions.java
│ │ │ ├── Policy.java
│ │ │ ├── PolicyBuilder.java
│ │ │ ├── PolicyConfig.java
│ │ │ ├── PolicyListeners.java
│ │ │ ├── RateLimitExceededException.java
│ │ │ ├── RateLimiter.java
│ │ │ ├── RateLimiterBuilder.java
│ │ │ ├── RateLimiterConfig.java
│ │ │ ├── RetryPolicy.java
│ │ │ ├── RetryPolicyBuilder.java
│ │ │ ├── RetryPolicyConfig.java
│ │ │ ├── SyncExecutionImpl.java
│ │ │ ├── Timeout.java
│ │ │ ├── TimeoutBuilder.java
│ │ │ ├── TimeoutConfig.java
│ │ │ ├── TimeoutExceededException.java
│ │ │ ├── event
│ │ │ ├── CircuitBreakerStateChangedEvent.java
│ │ │ ├── EventListener.java
│ │ │ ├── ExecutionAttemptedEvent.java
│ │ │ ├── ExecutionCompletedEvent.java
│ │ │ ├── ExecutionEvent.java
│ │ │ ├── ExecutionScheduledEvent.java
│ │ │ └── package-info.java
│ │ │ ├── function
│ │ │ ├── AsyncRunnable.java
│ │ │ ├── AsyncSupplier.java
│ │ │ ├── CheckedBiPredicate.java
│ │ │ ├── CheckedConsumer.java
│ │ │ ├── CheckedFunction.java
│ │ │ ├── CheckedPredicate.java
│ │ │ ├── CheckedRunnable.java
│ │ │ ├── CheckedSupplier.java
│ │ │ ├── ContextualRunnable.java
│ │ │ ├── ContextualSupplier.java
│ │ │ └── package-info.java
│ │ │ ├── internal
│ │ │ ├── BulkheadExecutor.java
│ │ │ ├── BulkheadImpl.java
│ │ │ ├── BurstyRateLimiterStats.java
│ │ │ ├── CircuitBreakerExecutor.java
│ │ │ ├── CircuitBreakerImpl.java
│ │ │ ├── CircuitState.java
│ │ │ ├── CircuitStats.java
│ │ │ ├── ClosedState.java
│ │ │ ├── CountingCircuitStats.java
│ │ │ ├── DefaultCircuitStats.java
│ │ │ ├── EventHandler.java
│ │ │ ├── FallbackExecutor.java
│ │ │ ├── FallbackImpl.java
│ │ │ ├── HalfOpenState.java
│ │ │ ├── OpenState.java
│ │ │ ├── RateLimiterExecutor.java
│ │ │ ├── RateLimiterImpl.java
│ │ │ ├── RateLimiterStats.java
│ │ │ ├── RetryPolicyExecutor.java
│ │ │ ├── RetryPolicyImpl.java
│ │ │ ├── SmoothRateLimiterStats.java
│ │ │ ├── TimedCircuitStats.java
│ │ │ ├── TimeoutExecutor.java
│ │ │ ├── TimeoutImpl.java
│ │ │ └── util
│ │ │ │ ├── Assert.java
│ │ │ │ ├── DelegatingScheduler.java
│ │ │ │ ├── Durations.java
│ │ │ │ ├── FutureLinkedList.java
│ │ │ │ ├── Lists.java
│ │ │ │ ├── Maths.java
│ │ │ │ └── RandomDelay.java
│ │ │ ├── package-info.java
│ │ │ └── spi
│ │ │ ├── AsyncExecutionInternal.java
│ │ │ ├── DefaultScheduledFuture.java
│ │ │ ├── DelayablePolicy.java
│ │ │ ├── ExecutionInternal.java
│ │ │ ├── ExecutionResult.java
│ │ │ ├── FailsafeFuture.java
│ │ │ ├── FailurePolicy.java
│ │ │ ├── PolicyExecutor.java
│ │ │ ├── Scheduler.java
│ │ │ ├── SyncExecutionInternal.java
│ │ │ └── package-info.java
│ └── javadoc
│ │ └── overview.html
│ └── test
│ └── java
│ └── dev
│ └── failsafe
│ ├── AsyncExecutionTest.java
│ ├── AsyncFailsafeTest.java
│ ├── BulkheadBuilderTest.java
│ ├── CircuitBreakerBuilderTest.java
│ ├── CircuitBreakerTest.java
│ ├── DelayablePolicyTest.java
│ ├── ExecutionTest.java
│ ├── FailsafeFutureTest.java
│ ├── FailsafeTest.java
│ ├── FailurePolicyBuilderTest.java
│ ├── FailurePolicyTest.java
│ ├── FallbackBuilderTest.java
│ ├── ListenersTest.java
│ ├── RateLimiterBuilderTest.java
│ ├── RetryPolicyBuilderTest.java
│ ├── TimeoutBuilderTest.java
│ ├── functional
│ ├── BlockedExecutionTest.java
│ ├── BulkheadTest.java
│ ├── CallCancellationTest.java
│ ├── CircuitBreakerTest.java
│ ├── DelayableCircuitBreakerTest.java
│ ├── DelayableRetryPolicyTest.java
│ ├── ExecutorConfigurationTest.java
│ ├── ExecutorTest.java
│ ├── FallbackTest.java
│ ├── FutureCancellationTest.java
│ ├── FutureCompletionTest.java
│ ├── InterruptionTest.java
│ ├── NestedCircuitBreakerTest.java
│ ├── NestedRetryPolicyTest.java
│ ├── NestedTimeoutTest.java
│ ├── NoPolicyTest.java
│ ├── PolicyCompositionExecutionTest.java
│ ├── PolicyCompositionTest.java
│ ├── RateLimiterTest.java
│ ├── RetryPolicyTest.java
│ ├── ShutdownExecutorTest.java
│ ├── TimeoutTest.java
│ └── package-info.java
│ ├── internal
│ ├── BurstyRateLimiterStatsTest.java
│ ├── CircuitStatsTest.java
│ ├── ClosedStateTest.java
│ ├── CountingCircuitStatsTest.java
│ ├── HalfOpenStateTest.java
│ ├── InternalTesting.java
│ ├── OpenStateTest.java
│ ├── RateLimiterImplTest.java
│ ├── RateLimiterStatsTest.java
│ ├── RetryPolicyImplTest.java
│ ├── SmoothRateLimiterStatsTest.java
│ ├── TimedCircuitStatsTest.java
│ └── util
│ │ ├── DelegatingSchedulerTest.java
│ │ ├── DurationsTest.java
│ │ ├── FutureLinkedListTest.java
│ │ ├── ListsTest.java
│ │ ├── MathsTest.java
│ │ └── RandomDelayTest.java
│ ├── issues
│ ├── Issue115Test.java
│ ├── Issue131Test.java
│ ├── Issue146Test.java
│ ├── Issue165Test.java
│ ├── Issue177Test.java
│ ├── Issue190Test.java
│ ├── Issue192Test.java
│ ├── Issue206Test.java
│ ├── Issue215Test.java
│ ├── Issue218Test.java
│ ├── Issue224Test.java
│ ├── Issue231Test.java
│ ├── Issue240Test.java
│ ├── Issue242Test.java
│ ├── Issue260Test.java
│ ├── Issue267Test.java
│ ├── Issue284Test.java
│ ├── Issue298Test.java
│ ├── Issue311Test.java
│ ├── Issue36Test.java
│ ├── Issue52Test.java
│ ├── Issue55Test.java
│ ├── Issue5Test.java
│ ├── Issue75Test.java
│ ├── Issue76Test.java
│ ├── Issue84Test.java
│ └── Issue9Test.java
│ └── testing
│ ├── Asserts.java
│ ├── Logging.java
│ ├── Mocking.java
│ ├── TestCaseLogger.java
│ ├── Testing.java
│ └── package-info.java
├── examples
├── pom.xml
└── src
│ └── main
│ └── java
│ └── dev
│ └── failsafe
│ └── examples
│ ├── AsyncExample.java
│ ├── Java8Example.java
│ ├── NettyExample.java
│ ├── RetryLoopExample.java
│ ├── RxJavaExample.java
│ └── VertxExample.java
├── modules
├── okhttp
│ ├── pom.xml
│ └── src
│ │ ├── main
│ │ └── java
│ │ │ └── dev
│ │ │ └── failsafe
│ │ │ └── okhttp
│ │ │ └── FailsafeCall.java
│ │ └── test
│ │ └── java
│ │ └── dev
│ │ └── failsafe
│ │ └── okhttp
│ │ ├── FailsafeCallTest.java
│ │ └── testing
│ │ └── OkHttpTesting.java
└── retrofit
│ ├── pom.xml
│ └── src
│ ├── main
│ └── java
│ │ └── dev
│ │ └── failsafe
│ │ └── retrofit
│ │ └── FailsafeCall.java
│ └── test
│ └── java
│ └── dev
│ └── retrofit
│ ├── FailsafeCallTest.java
│ ├── TestService.java
│ └── testing
│ └── RetrofitTesting.java
└── pom.xml
/.github/workflows/maven.yml:
--------------------------------------------------------------------------------
1 | # This workflow will build a Java project with Maven
2 | # For more information see: https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-maven
3 |
4 | name: build
5 |
6 | on: [push, pull_request]
7 |
8 | jobs:
9 | compile:
10 | runs-on: ubuntu-latest
11 |
12 | strategy:
13 | matrix:
14 | java: [ 8, 11, 17 ]
15 | jdk: ['temurin', 'zulu']
16 |
17 | name: Java ${{ matrix.java }} ${{ matrix.jdk }}
18 | steps:
19 | - name: Checkout Source Code
20 | uses: actions/checkout@v4
21 |
22 | - name: Setup Java
23 | uses: actions/setup-java@v4
24 | with:
25 | distribution: ${{ matrix.jdk }}
26 | java-package: jdk
27 | java-version: ${{ matrix.java }}
28 | cache: 'maven'
29 |
30 | - name: Build with maven
31 | run: mvn -B test
32 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | target/
2 | *~
3 | .project
4 | .classpath
5 | .settings/
6 | test-output/
7 | docs/
8 | .idea
9 | *.iml
10 | _site
11 | .java-version
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | ### Reporting Bugs
2 |
3 | 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.
4 |
5 | ### Contributing Bug Fixes
6 |
7 | Pull requests for bugs related to existing features are always welcome.
8 |
9 | ### Requesting Features
10 |
11 | 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.
12 |
13 | ### Contributing Features
14 |
15 | 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.
16 |
17 | If your feature idea sounds good, you can then submit a PR, else we'll schedule the feature for implementation.
18 |
19 | ### Contributing Documentation or Website Fixes
20 |
21 | 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.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Failsafe
2 |
3 | [](https://github.com/failsafe-lib/failsafe/actions)
4 | [](https://maven-badges.herokuapp.com/maven-central/dev.failsafe/failsafe)
5 | [](http://www.apache.org/licenses/LICENSE-2.0.html)
6 | [](https://failsafe-lib.slack.com)
7 | [](https://failsafe.dev/javadoc/core)
8 |
9 | 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.
10 |
11 | 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/).
12 |
13 | ## Usage
14 |
15 | Visit [failsafe.dev](https://failsafe.dev) for usage info, docs, and additional resources.
16 |
17 | ## Contributing
18 |
19 | Check out the [contributing guidelines](https://github.com/failsafe-lib/failsafe/blob/master/CONTRIBUTING.md).
20 |
21 | ## License
22 |
23 | Copyright Jonathan Halterman and friends. Released under the [Apache 2.0 license](https://github.com/failsafe-lib/failsafe/blob/master/LICENSE).
--------------------------------------------------------------------------------
/VERSIONING.md:
--------------------------------------------------------------------------------
1 | ### Versioning
2 |
3 | Failsafe follows MAJOR.MINOR.PATCH versioning where:
4 |
5 | - MAJOR versions contain significant new features and potentially significant incompatible API changes.
6 | - MINOR versions contain new features and potentially minor yet incompatible API changes.
7 | - PATCH versions contain bug fixes and minor new features that are fully backwards compatible.
8 |
9 | All versions, new features, and API changes are described in the [CHANGELOG](CHANGELOG.md).
--------------------------------------------------------------------------------
/bin/push-javadoc.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | # run from top level dir
3 |
4 | ORG=failsafe-lib
5 | REPO=failsafe.dev
6 |
7 | pwd=`pwd`
8 |
9 | build () {
10 | echo "Building Javadocs for $1"
11 | cd $pwd
12 | if [ "$1" != "core" ]; then
13 | cd modules
14 | fi
15 | cd $1
16 | mvn javadoc:javadoc -Djv=$apiVersion
17 | rm -rf target/docs
18 | git clone git@github.com:$ORG/$REPO.git target/docs
19 | cd target/docs
20 | git rm -rf javadoc/$1
21 | mkdir -p javadoc/$1
22 | mv -v ../site/apidocs/* javadoc/$1
23 |
24 | patchFavIcon "javadoc" "../assets/images/favicon.png"
25 | commit && echo "Published Javadocs for $1"
26 | }
27 |
28 | patchFavIcon () {
29 | echo "Patching favicons"
30 | for f in $1/*.html ; do
31 | if [ -f "$f" ]; then # if no .html files exist, f is literal "*.html"
32 | tmpfile=`mktemp patch_favicon_XXXXX`
33 | # This creates tmpfile, with the same permissions as $f.
34 | # The next command will overwrite it but preserve the permissions.
35 | # Hat tip to http://superuser.com/questions/170226/standard-way-to-duplicate-a-files-permissions for this trick.
36 | \cp -p $f $tmpfile
37 | sed -e " s%
\$%%" $f > $tmpfile
38 | DIFF=$(diff $f $tmpfile)
39 | if [ "$DIFF" != "" ]
40 | then
41 | echo "$f modified with favicon"
42 | fi
43 | mv -f $tmpfile $f
44 | fi;
45 | done ;
46 | for d in $1/* ; do
47 | if [ -d $d ]; then echo "descending to "$d ; patchFavIcon $d ../$2 ; fi ;
48 | done
49 | }
50 |
51 | commit() {
52 | echo "Committing javadocs"
53 | git add -A -f javadoc
54 | git commit -m "Updated JavaDocs"
55 | git push -fq > /dev/null
56 | }
57 |
58 | # Install parent and core
59 | echo "Installing parent and core artifacts"
60 | mvn install -N
61 | cd core
62 | mvn install -DskipTests=true
63 | cd ../
64 |
65 | build "core"
66 | build "okhttp"
67 | build "retrofit"
--------------------------------------------------------------------------------
/core/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 4.0.0
4 |
5 |
6 | dev.failsafe
7 | failsafe-parent
8 | 3.3.3-SNAPSHOT
9 |
10 |
11 | failsafe
12 | Failsafe
13 |
14 |
15 | ${project.groupId}.core
16 |
17 |
18 |
19 |
20 |
21 | org.moditect
22 | moditect-maven-plugin
23 |
24 |
25 | maven-jar-plugin
26 |
27 |
28 |
29 | test-jar
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
--------------------------------------------------------------------------------
/core/src/main/java/dev/failsafe/AsyncExecution.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2018 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License
15 | */
16 | package dev.failsafe;
17 |
18 | import java.util.concurrent.CompletableFuture;
19 |
20 | /**
21 | * Allows asynchronous executions to record their results or complete an execution.
22 | *
23 | * @param result type
24 | * @author Jonathan Halterman
25 | */
26 | public interface AsyncExecution extends ExecutionContext {
27 | /**
28 | * Completes the execution and the associated {@code CompletableFuture}.
29 | *
30 | * @throws IllegalStateException if the execution is already recorded or complete
31 | */
32 | void complete();
33 |
34 | /**
35 | * Returns whether the execution is complete or if it can be retried. An execution is considered complete only when
36 | * all configured policies consider the execution complete.
37 | */
38 | boolean isComplete();
39 |
40 | /**
41 | * Records an execution {@code result} or {@code exception} which triggers failure handling, if needed, by the
42 | * configured policies. If policy handling is not possible or already complete, the resulting {@link
43 | * CompletableFuture} is completed.
44 | *
45 | * @throws IllegalStateException if the most recent execution was already recorded or the execution is complete
46 | */
47 | void record(R result, Throwable exception);
48 |
49 | /**
50 | * Records an execution {@code result} which triggers failure handling, if needed, by the configured policies. If
51 | * policy handling is not possible or already complete, the resulting {@link CompletableFuture} is completed.
52 | *
53 | * @throws IllegalStateException if the most recent execution was already recorded or the execution is complete
54 | */
55 | void recordResult(R result);
56 |
57 | /**
58 | * Records an {@code exception} which triggers failure handling, if needed, by the configured policies. If policy
59 | * handling is not possible or already complete, the resulting {@link CompletableFuture} is completed.
60 | *
61 | * @throws IllegalStateException if the most recent execution was already recorded or the execution is complete
62 | */
63 | void recordException(Throwable exception);
64 | }
--------------------------------------------------------------------------------
/core/src/main/java/dev/failsafe/BulkheadBuilder.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2021 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License
15 | */
16 | package dev.failsafe;
17 |
18 | import dev.failsafe.internal.BulkheadImpl;
19 | import dev.failsafe.internal.util.Assert;
20 |
21 | import java.time.Duration;
22 |
23 | /**
24 | * Builds {@link Bulkhead} instances.
25 | *
26 | * This class is not threadsafe.
27 | *
28 | *
29 | * @param result type
30 | * @author Jonathan Halterman
31 | * @see BulkheadConfig
32 | * @see BulkheadFullException
33 | */
34 | public class BulkheadBuilder extends PolicyBuilder, BulkheadConfig, R> {
35 | BulkheadBuilder(int maxConcurrency) {
36 | super(new BulkheadConfig<>(maxConcurrency));
37 | }
38 |
39 | BulkheadBuilder(BulkheadConfig config) {
40 | super(new BulkheadConfig<>(config));
41 | }
42 |
43 | /**
44 | * Builds a new {@link Bulkhead} using the builder's configuration.
45 | */
46 | public Bulkhead build() {
47 | return new BulkheadImpl<>(new BulkheadConfig<>(config));
48 | }
49 |
50 | /**
51 | * Configures the {@code maxWaitTime} to wait for permits to be available. If permits cannot be acquired before the
52 | * {@code maxWaitTime} is exceeded, then the bulkhead will throw {@link BulkheadFullException}.
53 | *
54 | * This setting only applies when the resulting Bulkhead is used with the {@link Failsafe} class. It does not apply
55 | * when the Bulkhead is used in a standalone way.
56 | *
57 | *
58 | * @throws NullPointerException if {@code maxWaitTime} is null
59 | */
60 | public BulkheadBuilder withMaxWaitTime(Duration maxWaitTime) {
61 | config.maxWaitTime = Assert.notNull(maxWaitTime, "maxWaitTime");
62 | return this;
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/core/src/main/java/dev/failsafe/BulkheadConfig.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2021 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License
15 | */
16 | package dev.failsafe;
17 |
18 | import java.time.Duration;
19 |
20 | /**
21 | * Configuration for a {@link Bulkhead}.
22 | *
23 | * @param result type
24 | * @author Jonathan Halterman
25 | */
26 | public class BulkheadConfig extends PolicyConfig {
27 | int maxConcurrency;
28 | Duration maxWaitTime;
29 |
30 | BulkheadConfig(int maxConcurrency) {
31 | this.maxConcurrency = maxConcurrency;
32 | maxWaitTime = Duration.ZERO;
33 | }
34 |
35 | BulkheadConfig(BulkheadConfig config) {
36 | super(config);
37 | maxConcurrency = config.maxConcurrency;
38 | maxWaitTime = config.maxWaitTime;
39 | }
40 |
41 | /**
42 | * Returns that max concurrent executions that are permitted within the bulkhead.
43 | *
44 | * @see Bulkhead#builder(int)
45 | */
46 | public int getMaxConcurrency() {
47 | return maxConcurrency;
48 | }
49 |
50 | /**
51 | * Returns the max time to wait for permits to be available. If permits cannot be acquired before the max wait time is
52 | * exceeded, then the bulkhead will throw {@link BulkheadFullException}.
53 | *
54 | * This setting only applies when the Bulkhead is used with the {@link Failsafe} class. It does not apply when the
55 | * Bulkhead is used in a standalone way.
56 | *
57 | *
58 | * @see BulkheadBuilder#withMaxWaitTime(Duration)
59 | */
60 | public Duration getMaxWaitTime() {
61 | return maxWaitTime;
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/core/src/main/java/dev/failsafe/BulkheadFullException.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2021 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License
15 | */
16 | package dev.failsafe;
17 |
18 | /**
19 | * Thrown when an execution is attempted against a {@link Bulkhead} that is full.
20 | *
21 | * @author Jonathan Halterman
22 | */
23 | public class BulkheadFullException extends FailsafeException {
24 | private static final long serialVersionUID = 1L;
25 |
26 | private final Bulkhead> bulkhead;
27 |
28 | public BulkheadFullException(Bulkhead> bulkhead) {
29 | this.bulkhead = bulkhead;
30 | }
31 |
32 | /** Returns the {@link Bulkhead} that caused the exception. */
33 | public Bulkhead> getBulkhead() {
34 | return bulkhead;
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/core/src/main/java/dev/failsafe/Call.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2022 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License
15 | */
16 | package dev.failsafe;
17 |
18 | import dev.failsafe.function.CheckedRunnable;
19 |
20 | /**
21 | * A call that can perform Failsafe executions and can be cancelled. Cancellations are propagated to any {@link
22 | * ExecutionContext#onCancel(CheckedRunnable) cancelCallback} that is registered. Useful for integrating with libraries
23 | * that support cancellation.
24 | *
25 | * To perform cancellable async executions, use the {@link FailsafeExecutor} async methods.
26 | *
27 | *
28 | * @param result type
29 | * @author Jonathan Halterman
30 | */
31 | public interface Call {
32 | /**
33 | * Executes the call until a successful result is returned or the configured policies are exceeded.
34 | *
35 | * @throws FailsafeException if the execution fails with a checked Exception. {@link FailsafeException#getCause()} can
36 | * be used to learn the underlying checked exception.
37 | */
38 | R execute();
39 |
40 | /**
41 | * Cancels a synchronous execution and calls the most recent {@link ExecutionContext#onCancel(CheckedRunnable)
42 | * cancelCallback} that was registered. The execution is still allowed to complete and return a result. In addition to
43 | * using a {@link ExecutionContext#onCancel(CheckedRunnable) cancelCallback}, executions can cooperate with
44 | * cancellation by checking {@link ExecutionContext#isCancelled()}.
45 | *
46 | * @param mayInterruptIfRunning whether the execution should be interrupted
47 | * @return whether cancellation was successful or not. Returns {@code false} if the execution was already cancelled or
48 | * completed.
49 | */
50 | boolean cancel(boolean mayInterruptIfRunning);
51 |
52 | /**
53 | * Returns whether the call has been cancelled.
54 | */
55 | boolean isCancelled();
56 | }
57 |
--------------------------------------------------------------------------------
/core/src/main/java/dev/failsafe/CallImpl.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2022 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License
15 | */
16 | package dev.failsafe;
17 |
18 | /**
19 | * A call implementation that delegates to an execution.
20 | *
21 | * @param result type
22 | * @author Jonathan Halterman
23 | */
24 | class CallImpl implements Call {
25 | private volatile SyncExecutionImpl execution;
26 |
27 | void setExecution(SyncExecutionImpl execution) {
28 | this.execution = execution;
29 | }
30 |
31 | @Override
32 | public R execute() {
33 | return execution.executeSync();
34 | }
35 |
36 | @Override
37 | public boolean cancel(boolean mayInterruptIfRunning) {
38 | boolean result = execution.cancel();
39 | if (mayInterruptIfRunning)
40 | execution.interrupt();
41 | return result;
42 | }
43 |
44 | @Override
45 | public boolean isCancelled() {
46 | return execution.isCancelled();
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/core/src/main/java/dev/failsafe/CircuitBreakerOpenException.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2016 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License
15 | */
16 | package dev.failsafe;
17 |
18 | /**
19 | * Thrown when an execution is attempted against a {@link CircuitBreaker} that is open.
20 | *
21 | * @author Jonathan Halterman
22 | */
23 | public class CircuitBreakerOpenException extends FailsafeException {
24 | private static final long serialVersionUID = 1L;
25 |
26 | private final CircuitBreaker> circuitBreaker;
27 |
28 | public CircuitBreakerOpenException(CircuitBreaker> circuitBreaker) {
29 | this.circuitBreaker = circuitBreaker;
30 | }
31 |
32 | /** Returns the {@link CircuitBreaker} that caused the exception. */
33 | public CircuitBreaker> getCircuitBreaker() {
34 | return circuitBreaker;
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/core/src/main/java/dev/failsafe/DelayablePolicyConfig.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2018 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License
15 | */
16 | package dev.failsafe;
17 |
18 | import dev.failsafe.function.ContextualSupplier;
19 |
20 | import java.time.Duration;
21 |
22 | /**
23 | * Configuration for policies that can delay between executions.
24 | *
25 | * @param result type
26 | * @author Jonathan Halterman
27 | */
28 | public abstract class DelayablePolicyConfig extends FailurePolicyConfig {
29 | Duration delay;
30 | R delayResult;
31 | Class extends Throwable> delayException;
32 | ContextualSupplier delayFn;
33 |
34 | protected DelayablePolicyConfig() {
35 | }
36 |
37 | protected DelayablePolicyConfig(DelayablePolicyConfig config) {
38 | super(config);
39 | delay = config.delay;
40 | delayResult = config.delayResult;
41 | delayException = config.delayException;
42 | delayFn = config.delayFn;
43 | }
44 |
45 | /**
46 | * Returns the delay until the next execution attempt can be performed.
47 | *
48 | * @see DelayablePolicyBuilder#withDelay(Duration)
49 | */
50 | public Duration getDelay() {
51 | return delay;
52 | }
53 |
54 | /**
55 | * Returns the function that determines the next delay before another execution can be performed.
56 | *
57 | * @see DelayablePolicyBuilder#withDelayFn(ContextualSupplier)
58 | * @see DelayablePolicyBuilder#withDelayFnOn(ContextualSupplier, Class)
59 | * @see DelayablePolicyBuilder#withDelayFnWhen(ContextualSupplier, Object)
60 | */
61 | public ContextualSupplier getDelayFn() {
62 | return delayFn;
63 | }
64 |
65 | /**
66 | * Returns the Throwable that must be matched in order to delay using the {@link #getDelayFn()}.
67 | *
68 | * @see DelayablePolicyBuilder#withDelayFnOn(ContextualSupplier, Class)
69 | */
70 | public Class extends Throwable> getDelayException() {
71 | return delayException;
72 | }
73 |
74 | /**
75 | * Returns the result that must be matched in order to delay using the {@link #getDelayFn()}.
76 | *
77 | * @see DelayablePolicyBuilder#withDelayFnWhen(ContextualSupplier, Object)
78 | */
79 | public R getDelayResult() {
80 | return delayResult;
81 | }
82 | }
83 |
--------------------------------------------------------------------------------
/core/src/main/java/dev/failsafe/FailsafeException.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2016 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License
15 | */
16 | package dev.failsafe;
17 |
18 | /**
19 | * Thrown when a synchronous Failsafe execution fails with an {@link Exception}, wrapping the underlying exception. Use
20 | * {@link Throwable#getCause()} to learn the cause of the failure.
21 | *
22 | * @author Jonathan Halterman
23 | */
24 | public class FailsafeException extends RuntimeException {
25 | private static final long serialVersionUID = 1L;
26 |
27 | public FailsafeException() {
28 | }
29 |
30 | public FailsafeException(Throwable t) {
31 | super(t);
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/core/src/main/java/dev/failsafe/FailurePolicyConfig.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2018 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License
15 | */
16 | package dev.failsafe;
17 |
18 | import dev.failsafe.function.CheckedBiPredicate;
19 | import dev.failsafe.function.CheckedPredicate;
20 |
21 | import java.util.ArrayList;
22 | import java.util.List;
23 |
24 | /**
25 | * Configuration for policies that handle specific failures and conditions.
26 | *
27 | * @param result type
28 | * @author Jonathan Halterman
29 | */
30 | public abstract class FailurePolicyConfig extends PolicyConfig {
31 | /** Indicates whether exceptions are checked by a configured failure condition */
32 | boolean exceptionsChecked;
33 | /** Conditions that determine whether an execution is a failure */
34 | List> failureConditions;
35 |
36 | protected FailurePolicyConfig() {
37 | failureConditions = new ArrayList<>();
38 | }
39 |
40 | protected FailurePolicyConfig(FailurePolicyConfig config) {
41 | super(config);
42 | exceptionsChecked = config.exceptionsChecked;
43 | failureConditions = new ArrayList<>(config.failureConditions);
44 | }
45 |
46 | /**
47 | * Returns whether exceptions are checked by a configured failure condition.
48 | */
49 | public boolean isExceptionsChecked() {
50 | return exceptionsChecked;
51 | }
52 |
53 | /**
54 | * Returns the conditions under which a result or Throwable should be treated as a failure and handled.
55 | *
56 | * @see FailurePolicyBuilder#handle(Class...)
57 | * @see FailurePolicyBuilder#handle(List)
58 | * @see FailurePolicyBuilder#handleIf(CheckedBiPredicate)
59 | * @see FailurePolicyBuilder#handleIf(CheckedPredicate)
60 | * @see FailurePolicyBuilder#handleResult(Object)
61 | * @see FailurePolicyBuilder#handleResultIf(CheckedPredicate)
62 | */
63 | public List> getFailureConditions() {
64 | return failureConditions;
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/core/src/main/java/dev/failsafe/Policy.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2018 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License
15 | */
16 | package dev.failsafe;
17 |
18 | import dev.failsafe.spi.PolicyExecutor;
19 |
20 | /**
21 | * A policy for handling executions.
22 | *
23 | * @param result type
24 | * @author Jonathan Halterman
25 | */
26 | public interface Policy {
27 | /**
28 | * Returns the policy config.
29 | */
30 | PolicyConfig getConfig();
31 |
32 | /**
33 | * Returns a {@link PolicyExecutor} capable of handling an execution for the Policy.
34 | */
35 | PolicyExecutor toExecutor(int policyIndex);
36 | }
37 |
--------------------------------------------------------------------------------
/core/src/main/java/dev/failsafe/PolicyBuilder.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2018 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License
15 | */
16 | package dev.failsafe;
17 |
18 | import dev.failsafe.event.EventListener;
19 | import dev.failsafe.internal.util.Assert;
20 | import dev.failsafe.event.ExecutionCompletedEvent;
21 |
22 | /**
23 | * Builds policies.
24 | *
25 | * @param self type
26 | * @param config type
27 | * @param result type
28 | * @author Jonathan Halterman
29 | */
30 | @SuppressWarnings("unchecked")
31 | public abstract class PolicyBuilder, R> implements PolicyListeners {
32 | protected C config;
33 |
34 | protected PolicyBuilder(C config) {
35 | this.config = config;
36 | }
37 |
38 | public S onFailure(EventListener> listener) {
39 | config.failureListener = Assert.notNull(listener, "listener");
40 | return (S) this;
41 | }
42 |
43 | @Override
44 | public S onSuccess(EventListener> listener) {
45 | config.successListener = Assert.notNull(listener, "listener");
46 | return (S) this;
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/core/src/main/java/dev/failsafe/PolicyConfig.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2018 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License
15 | */
16 | package dev.failsafe;
17 |
18 | import dev.failsafe.event.EventListener;
19 | import dev.failsafe.event.ExecutionCompletedEvent;
20 |
21 | /**
22 | * Configuration for a {@link Policy}.
23 | *
24 | * @param result type
25 | * @author Jonathan Halterman
26 | */
27 | public abstract class PolicyConfig {
28 | volatile EventListener> successListener;
29 | volatile EventListener> failureListener;
30 |
31 | protected PolicyConfig() {
32 | }
33 |
34 | protected PolicyConfig(PolicyConfig config) {
35 | successListener = config.successListener;
36 | failureListener = config.failureListener;
37 | }
38 |
39 | /**
40 | * Returns the success listener.
41 | *
42 | * @see PolicyListeners#onSuccess(EventListener)
43 | */
44 | public EventListener> getSuccessListener() {
45 | return successListener;
46 | }
47 |
48 | /**
49 | * Returns the failure listener.
50 | *
51 | * @see PolicyListeners#onFailure(EventListener)
52 | */
53 | public EventListener> getFailureListener() {
54 | return failureListener;
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/core/src/main/java/dev/failsafe/PolicyListeners.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2018 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License
15 | */
16 | package dev.failsafe;
17 |
18 | import dev.failsafe.event.EventListener;
19 | import dev.failsafe.event.ExecutionCompletedEvent;
20 |
21 | /**
22 | * Configures listeners for a policy execution result.
23 | *
24 | * @param self type
25 | * @param result type
26 | * @author Jonathan Halterman
27 | */
28 | public interface PolicyListeners {
29 | /**
30 | * Registers the {@code listener} to be called when the policy fails to handle an execution. This means that not only
31 | * was the supplied execution considered a failure by the policy, but that the policy was unable to produce a
32 | * successful result.
33 | *
Note: Any exceptions that are thrown from within the {@code listener} are ignored. To provide an alternative
34 | * result for a failed execution, use a {@link Fallback}.
35 | */
36 | S onFailure(EventListener> listener);
37 |
38 | /**
39 | * Registers the {@code listener} to be called when the policy succeeds in handling an execution. This means that the
40 | * supplied execution either succeeded, or if it failed, the policy was able to produce a successful result.
41 | *
Note: Any exceptions that are thrown from within the {@code listener} are ignored.
42 | */
43 | S onSuccess(EventListener> listener);
44 | }
45 |
--------------------------------------------------------------------------------
/core/src/main/java/dev/failsafe/RateLimitExceededException.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2021 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License
15 | */
16 | package dev.failsafe;
17 |
18 | /**
19 | * Thrown when an execution exceeds or would exceed a {@link RateLimiter}.
20 | *
21 | * @author Jonathan Halterman
22 | */
23 | public class RateLimitExceededException extends FailsafeException {
24 | private static final long serialVersionUID = 1L;
25 |
26 | private final RateLimiter> rateLimiter;
27 |
28 | public RateLimitExceededException(RateLimiter> rateLimiter) {
29 | this.rateLimiter = rateLimiter;
30 | }
31 |
32 | /** Returns the {@link RateLimiter} that caused the exception. */
33 | public RateLimiter> getRateLimiter() {
34 | return rateLimiter;
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/core/src/main/java/dev/failsafe/RateLimiterBuilder.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2021 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License
15 | */
16 | package dev.failsafe;
17 |
18 | import dev.failsafe.internal.RateLimiterImpl;
19 | import dev.failsafe.internal.util.Assert;
20 |
21 | import java.time.Duration;
22 |
23 | /**
24 | * Builds {@link RateLimiter} instances.
25 | *
26 | * This class is not threadsafe.
27 | *
28 | *
29 | * @param result type
30 | * @author Jonathan Halterman
31 | * @see RateLimiterConfig
32 | * @see RateLimitExceededException
33 | */
34 | public class RateLimiterBuilder extends PolicyBuilder, RateLimiterConfig, R> {
35 | RateLimiterBuilder(Duration executionRate) {
36 | super(new RateLimiterConfig<>(executionRate));
37 | config.maxWaitTime = Duration.ZERO;
38 | }
39 |
40 | RateLimiterBuilder(long maxPermits, Duration period) {
41 | super(new RateLimiterConfig<>(maxPermits, period));
42 | config.maxWaitTime = Duration.ZERO;
43 | }
44 |
45 | RateLimiterBuilder(RateLimiterConfig config) {
46 | super(new RateLimiterConfig<>(config));
47 | }
48 |
49 | /**
50 | * Builds a new {@link RateLimiter} using the builder's configuration.
51 | */
52 | public RateLimiter build() {
53 | return new RateLimiterImpl<>(new RateLimiterConfig<>(config));
54 | }
55 |
56 | /**
57 | * Configures the {@code maxWaitTime} to wait for permits to be available. If permits cannot be acquired before the
58 | * {@code maxWaitTime} is exceeded, then the rate limiter will throw {@link RateLimitExceededException}.
59 | *
60 | * This setting only applies when the resulting RateLimiter is used with the {@link Failsafe} class. It does not apply
61 | * when the RateLimiter is used in a standalone way.
62 | *
63 | *
64 | * @throws NullPointerException if {@code maxWaitTime} is null
65 | */
66 | public RateLimiterBuilder withMaxWaitTime(Duration maxWaitTime) {
67 | config.maxWaitTime = Assert.notNull(maxWaitTime, "maxWaitTime");
68 | return this;
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/core/src/main/java/dev/failsafe/RetryPolicy.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2016 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License
15 | */
16 | package dev.failsafe;
17 |
18 | /**
19 | * A policy that defines when retries should be performed. See {@link RetryPolicyBuilder} for configuration options.
20 | *
21 | * This class is threadsafe.
22 | *
23 | *
24 | * @param result type
25 | * @author Jonathan Halterman
26 | * @see RetryPolicyConfig
27 | * @see RetryPolicyBuilder
28 | */
29 | public interface RetryPolicy extends Policy {
30 | /**
31 | * Creates a RetryPolicyBuilder that by default will build a RetryPolicy that allows 3 execution attempts max with no
32 | * delay, unless configured otherwise.
33 | *
34 | * @see #ofDefaults()
35 | */
36 | static RetryPolicyBuilder builder() {
37 | return new RetryPolicyBuilder<>();
38 | }
39 |
40 | /**
41 | * Creates a new RetryPolicyBuilder that will be based on the {@code config}.
42 | */
43 | static RetryPolicyBuilder builder(RetryPolicyConfig config) {
44 | return new RetryPolicyBuilder<>(config);
45 | }
46 |
47 | /**
48 | * Creates a RetryPolicy that allows 3 execution attempts max with no delay. To configure additional options on a
49 | * RetryPolicy, use {@link #builder()} instead.
50 | *
51 | * @see #builder()
52 | */
53 | static RetryPolicy ofDefaults() {
54 | return RetryPolicy.builder().build();
55 | }
56 |
57 | /**
58 | * Returns the {@link RetryPolicyConfig} that the RetryPolicy was built with.
59 | */
60 | @Override
61 | RetryPolicyConfig getConfig();
62 | }
63 |
--------------------------------------------------------------------------------
/core/src/main/java/dev/failsafe/TimeoutBuilder.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2018 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License
15 | */
16 | package dev.failsafe;
17 |
18 | import dev.failsafe.function.AsyncRunnable;
19 | import dev.failsafe.internal.TimeoutImpl;
20 |
21 | import java.time.Duration;
22 |
23 | /**
24 | * Builds {@link Timeout} instances.
25 | *
26 | * This class is not threadsafe.
27 | *
28 | *
29 | * @param result type
30 | * @author Jonathan Halterman
31 | * @see TimeoutConfig
32 | * @see TimeoutExceededException
33 | */
34 | public class TimeoutBuilder extends PolicyBuilder, TimeoutConfig, R> {
35 | TimeoutBuilder(Duration timeout) {
36 | super(new TimeoutConfig<>(timeout, false));
37 | }
38 |
39 | TimeoutBuilder(TimeoutConfig config) {
40 | super(new TimeoutConfig<>(config));
41 | }
42 |
43 | /**
44 | * Builds a new {@link Timeout} using the builder's configuration.
45 | */
46 | public Timeout build() {
47 | return new TimeoutImpl<>(new TimeoutConfig<>(config));
48 | }
49 |
50 | /**
51 | * Configures the policy to interrupt an execution in addition to cancelling it when the timeout is exceeded. For
52 | * synchronous executions this is done by calling {@link Thread#interrupt()} on the execution's thread. For
53 | * asynchronous executions this is done by calling {@link java.util.concurrent.Future#cancel(boolean)
54 | * Future.cancel(true)}. Executions can internally cooperate with interruption by checking {@link
55 | * Thread#isInterrupted()} or by handling {@link InterruptedException} where available.
56 | *
57 | * Note: Only configure interrupts if the code being executed is designed to be interrupted.
58 | *
59 | *
Note: interruption will have no effect when performing an {@link
60 | * FailsafeExecutor#getAsyncExecution(AsyncRunnable) async execution} since the async thread is unknown to
61 | * Failsafe.
62 | */
63 | public TimeoutBuilder withInterrupt() {
64 | config.canInterrupt = true;
65 | return this;
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/core/src/main/java/dev/failsafe/TimeoutConfig.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2018 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License
15 | */
16 | package dev.failsafe;
17 |
18 | import java.time.Duration;
19 |
20 | /**
21 | * Configuration for a {@link Timeout}.
22 | *
23 | * This class is threadsafe.
24 | *
25 | *
26 | * @param result type
27 | * @author Jonathan Halterman
28 | * @see TimeoutBuilder
29 | */
30 | public class TimeoutConfig extends PolicyConfig {
31 | Duration timeout;
32 | boolean canInterrupt;
33 |
34 | TimeoutConfig(Duration timeout, boolean canInterrupt) {
35 | this.timeout = timeout;
36 | this.canInterrupt = canInterrupt;
37 | }
38 |
39 | TimeoutConfig(TimeoutConfig config) {
40 | super(config);
41 | timeout = config.timeout;
42 | canInterrupt = config.canInterrupt;
43 | }
44 |
45 | /**
46 | * Returns the timeout duration.
47 | */
48 | public Duration getTimeout() {
49 | return timeout;
50 | }
51 |
52 | /**
53 | * Returns whether the policy can interrupt an execution if the timeout is exceeded.
54 | *
55 | * @see TimeoutBuilder#withInterrupt()
56 | */
57 | public boolean canInterrupt() {
58 | return canInterrupt;
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/core/src/main/java/dev/failsafe/TimeoutExceededException.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2019 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License
15 | */
16 | package dev.failsafe;
17 |
18 | /**
19 | * Thrown when an execution exceeds a configured {@link Timeout}.
20 | *
21 | * @author Jonathan Halterman
22 | */
23 | public class TimeoutExceededException extends FailsafeException {
24 | private static final long serialVersionUID = 1L;
25 |
26 | private final Timeout> timeout;
27 |
28 | public TimeoutExceededException(Timeout> timeout) {
29 | this.timeout = timeout;
30 | }
31 |
32 | /** Returns the {@link Timeout} that caused the exception. */
33 | public Timeout> getTimeout() {
34 | return timeout;
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/core/src/main/java/dev/failsafe/event/CircuitBreakerStateChangedEvent.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2018 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License
15 | */
16 | package dev.failsafe.event;
17 |
18 | import dev.failsafe.CircuitBreaker.State;
19 |
20 | /**
21 | * Indicates a circuit breaker's state changed.
22 | *
23 | * @author Jonathan Halterman
24 | */
25 | public class CircuitBreakerStateChangedEvent {
26 | private final State previousState;
27 |
28 | public CircuitBreakerStateChangedEvent(State previousState) {
29 | this.previousState = previousState;
30 | }
31 |
32 | /**
33 | * Returns the previous state of the circuit breaker.
34 | */
35 | public State getPreviousState() {
36 | return previousState;
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/core/src/main/java/dev/failsafe/event/EventListener.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2018 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License
15 | */
16 | package dev.failsafe.event;
17 |
18 | /**
19 | * Listens for events.
20 | *
21 | * @param event type
22 | */
23 | @FunctionalInterface
24 | public interface EventListener {
25 | void accept(E event) throws Throwable;
26 |
27 | /**
28 | * Accepts an {@code event} and ignores any exceptions that result.
29 | */
30 | default void acceptUnchecked(E event) {
31 | try {
32 | accept(event);
33 | } catch (Throwable ignore) {
34 | }
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/core/src/main/java/dev/failsafe/event/ExecutionAttemptedEvent.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2018 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License
15 | */
16 | package dev.failsafe.event;
17 |
18 | import dev.failsafe.ExecutionContext;
19 |
20 | /**
21 | * Indicates an execution was attempted.
22 | *
23 | * @param result type
24 | * @author Jonathan Halterman
25 | */
26 | public class ExecutionAttemptedEvent extends ExecutionEvent {
27 | private final R result;
28 | private final Throwable exception;
29 |
30 | public ExecutionAttemptedEvent(R result, Throwable exception, ExecutionContext context) {
31 | super(context);
32 | this.result = result;
33 | this.exception = exception;
34 | }
35 |
36 | /**
37 | * Returns the failure that preceded the event, else {@code null} if there was none.
38 | */
39 | public Throwable getLastException() {
40 | return exception;
41 | }
42 |
43 | /**
44 | * Returns the result that preceded the event, else {@code null} if there was none.
45 | */
46 | public R getLastResult() {
47 | return result;
48 | }
49 |
50 | @Override
51 | public String toString() {
52 | return "ExecutionAttemptedEvent[" + "result=" + result + ", exception=" + exception + ']';
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/core/src/main/java/dev/failsafe/event/ExecutionCompletedEvent.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2018 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License
15 | */
16 | package dev.failsafe.event;
17 |
18 | import dev.failsafe.ExecutionContext;
19 |
20 | /**
21 | * Indicates an execution was completed or cancelled.
22 | *
23 | * @param result type
24 | * @author Jonathan Halterman
25 | */
26 | public class ExecutionCompletedEvent extends ExecutionEvent {
27 | private final R result;
28 | private final Throwable exception;
29 |
30 | public ExecutionCompletedEvent(R result, Throwable exception, ExecutionContext context) {
31 | super(context);
32 | this.result = result;
33 | this.exception = exception;
34 | }
35 |
36 | /**
37 | * Returns the failure that preceded the event, else {@code null} if there was none.
38 | */
39 | public Throwable getException() {
40 | return exception;
41 | }
42 |
43 | /**
44 | * Returns the result that preceded the event, else {@code null} if there was none.
45 | */
46 | public R getResult() {
47 | return result;
48 | }
49 |
50 | @Override
51 | public String toString() {
52 | return "ExecutionCompletedEvent[" + "result=" + result + ", exception=" + exception + ']';
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/core/src/main/java/dev/failsafe/event/ExecutionEvent.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2018 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License
15 | */
16 | package dev.failsafe.event;
17 |
18 | import dev.failsafe.CircuitBreaker;
19 | import dev.failsafe.ExecutionContext;
20 |
21 | import java.time.Duration;
22 | import java.time.Instant;
23 | import java.util.Optional;
24 |
25 | /**
26 | * Encapsulates information about a Failsafe execution.
27 | *
28 | * @author Jonathan Halterman
29 | */
30 | public abstract class ExecutionEvent {
31 | private final ExecutionContext> context;
32 |
33 | ExecutionEvent(ExecutionContext> context) {
34 | this.context = context;
35 | }
36 |
37 | /**
38 | * Returns the elapsed time since initial execution began.
39 | */
40 | public Duration getElapsedTime() {
41 | return context.getElapsedTime();
42 | }
43 |
44 | /**
45 | * Gets the number of execution attempts so far, including attempts that are blocked before being executed, such as
46 | * when a {@link CircuitBreaker CircuitBreaker} is open. Will return {@code 0} when the first
47 | * attempt is in progress or has yet to begin.
48 | */
49 | public int getAttemptCount() {
50 | return context.getAttemptCount();
51 | }
52 |
53 | /**
54 | * Gets the number of completed executions so far. Executions that are blocked, such as when a {@link
55 | * CircuitBreaker CircuitBreaker} is open, are not counted. Will return {@code 0} when the first
56 | * attempt is in progress or has yet to begin.
57 | */
58 | public int getExecutionCount() {
59 | return context.getExecutionCount();
60 | }
61 |
62 | /**
63 | * Returns the time that the initial execution started, else {@link Optional#empty()} if an execution has not started yet.
64 | */
65 | public Optional getStartTime() {
66 | return Optional.ofNullable(context.getStartTime());
67 | }
68 |
69 | /**
70 | * Returns the elapsed time since the last execution attempt began.
71 | */
72 | public Duration getElapsedAttemptTime() {
73 | return context.getElapsedAttemptTime();
74 | }
75 |
76 | /**
77 | * Returns {@code true} when {@link #getAttemptCount()} is {@code 0} meaning this is the first execution attempt.
78 | */
79 | public boolean isFirstAttempt() {
80 | return context.isFirstAttempt();
81 | }
82 |
83 | /**
84 | * Returns {@code true} when {@link #getAttemptCount()} is {@code > 0} meaning the execution is being retried.
85 | */
86 | public boolean isRetry() {
87 | return context.isRetry();
88 | }
89 | }
90 |
--------------------------------------------------------------------------------
/core/src/main/java/dev/failsafe/event/ExecutionScheduledEvent.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2018 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License
15 | */
16 | package dev.failsafe.event;
17 |
18 | import dev.failsafe.ExecutionContext;
19 | import dev.failsafe.Timeout;
20 | import dev.failsafe.spi.Scheduler;
21 |
22 | import java.time.Duration;
23 |
24 | /**
25 | * Indicates an execution was scheduled. A scheduled execution will be executed after the {@link #getDelay() delay}
26 | * unless it is cancelled, either explicitly or via {@link java.util.concurrent.Future#cancel(boolean)
27 | * Future.cancel(boolean)}, a {@link Timeout Timeout}, or if the underlying {@link Scheduler Scheduler} or {@link
28 | * java.util.concurrent.ExecutorService ExecutorService} is shutdown.
29 | *
30 | * @param result type
31 | * @author Jonathan Halterman
32 | */
33 | public class ExecutionScheduledEvent extends ExecutionEvent {
34 | private final R result;
35 | private final Throwable exception;
36 | private final Duration delay;
37 |
38 | public ExecutionScheduledEvent(R result, Throwable exception, Duration delay, ExecutionContext context) {
39 | super(context);
40 | this.result = result;
41 | this.exception = exception;
42 | this.delay = delay;
43 | }
44 |
45 | /**
46 | * Returns the failure that preceded the event, else {@code null} if there was none.
47 | */
48 | public Throwable getLastException() {
49 | return exception;
50 | }
51 |
52 | /**
53 | * Returns the result that preceded the event, else {@code null} if there was none.
54 | */
55 | public R getLastResult() {
56 | return result;
57 | }
58 |
59 | /**
60 | * Returns the delay before the next execution attempt.
61 | */
62 | public Duration getDelay() {
63 | return delay;
64 | }
65 |
66 | @Override
67 | public String toString() {
68 | return "ExecutionScheduledEvent[" + "result=" + result + ", exception=" + exception + ", delay=" + delay + ']';
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/core/src/main/java/dev/failsafe/event/package-info.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Event listener types.
3 | */
4 | package dev.failsafe.event;
5 |
--------------------------------------------------------------------------------
/core/src/main/java/dev/failsafe/function/AsyncRunnable.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2016 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License
15 | */
16 | package dev.failsafe.function;
17 |
18 | import dev.failsafe.AsyncExecution;
19 |
20 | /**
21 | * A Runnable that manually triggers asynchronous retries or completion via an asynchronous execution.
22 | *
23 | * @param result type
24 | * @author Jonathan Halterman
25 | */
26 | @FunctionalInterface
27 | public interface AsyncRunnable {
28 | void run(AsyncExecution execution) throws Exception;
29 | }
30 |
--------------------------------------------------------------------------------
/core/src/main/java/dev/failsafe/function/AsyncSupplier.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2016 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License
15 | */
16 | package dev.failsafe.function;
17 |
18 | import dev.failsafe.AsyncExecution;
19 |
20 | /**
21 | * A Supplier that manually triggers asynchronous retries or completion via an asynchronous execution.
22 | *
23 | * @param result type
24 | * @param supplied type
25 | * @author Jonathan Halterman
26 | */
27 | @FunctionalInterface
28 | public interface AsyncSupplier {
29 | T get(AsyncExecution execution) throws Exception;
30 | }
31 |
--------------------------------------------------------------------------------
/core/src/main/java/dev/failsafe/function/CheckedBiPredicate.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2016 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License
15 | */
16 | package dev.failsafe.function;
17 |
18 | /**
19 | * A BiPredicate that throws checked exceptions.
20 | *
21 | * @param first input type
22 | * @param second input type
23 | * @author Jonathan Halterman
24 | */
25 | @FunctionalInterface
26 | public interface CheckedBiPredicate {
27 | boolean test(T t, U u) throws Throwable;
28 | }
29 |
--------------------------------------------------------------------------------
/core/src/main/java/dev/failsafe/function/CheckedConsumer.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2016 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License
15 | */
16 | package dev.failsafe.function;
17 |
18 | /**
19 | * A Consumer that throws checked exceptions.
20 | *
21 | * @author Jonathan Halterman
22 | * @param input type
23 | */
24 | @FunctionalInterface
25 | public interface CheckedConsumer {
26 | void accept(T t) throws Throwable;
27 | }
--------------------------------------------------------------------------------
/core/src/main/java/dev/failsafe/function/CheckedFunction.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2016 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License
15 | */
16 | package dev.failsafe.function;
17 |
18 | /**
19 | * A Function that throws checked exceptions.
20 | *
21 | * @author Jonathan Halterman
22 | * @param input type
23 | * @param result type
24 | */
25 | @FunctionalInterface
26 | public interface CheckedFunction {
27 | R apply(T t) throws Throwable;
28 | }
29 |
--------------------------------------------------------------------------------
/core/src/main/java/dev/failsafe/function/CheckedPredicate.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2016 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License
15 | */
16 | package dev.failsafe.function;
17 |
18 | /**
19 | * A Predicate that throws checked exceptions.
20 | *
21 | * @param input type
22 | * @author Jonathan Halterman
23 | */
24 | @FunctionalInterface
25 | public interface CheckedPredicate {
26 | boolean test(T t) throws Throwable;
27 | }
28 |
--------------------------------------------------------------------------------
/core/src/main/java/dev/failsafe/function/CheckedRunnable.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2016 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License
15 | */
16 | package dev.failsafe.function;
17 |
18 | /**
19 | * A Runnable that throws checked exceptions.
20 | *
21 | * @author Jonathan Halterman
22 | */
23 | @FunctionalInterface
24 | public interface CheckedRunnable {
25 | void run() throws Throwable;
26 | }
27 |
--------------------------------------------------------------------------------
/core/src/main/java/dev/failsafe/function/CheckedSupplier.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2016 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License
15 | */
16 | package dev.failsafe.function;
17 |
18 | /**
19 | * A Supplier that throws checked exceptions.
20 | *
21 | * @param supplied type
22 | * @author Jonathan Halterman
23 | */
24 | @FunctionalInterface
25 | public interface CheckedSupplier {
26 | T get() throws Throwable;
27 | }
28 |
--------------------------------------------------------------------------------
/core/src/main/java/dev/failsafe/function/ContextualRunnable.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2016 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License
15 | */
16 | package dev.failsafe.function;
17 |
18 | import dev.failsafe.ExecutionContext;
19 |
20 | /**
21 | * A Runnable that provides execution context.
22 | *
23 | * @param result type
24 | * @author Jonathan Halterman
25 | */
26 | @FunctionalInterface
27 | public interface ContextualRunnable {
28 | void run(ExecutionContext context) throws Throwable;
29 | }
30 |
--------------------------------------------------------------------------------
/core/src/main/java/dev/failsafe/function/ContextualSupplier.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2016 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License
15 | */
16 | package dev.failsafe.function;
17 |
18 | import dev.failsafe.ExecutionContext;
19 |
20 | /**
21 | * A Supplier that provides execution context.
22 | *
23 | * @param result type
24 | * @param supplied type
25 | * @author Jonathan Halterman
26 | */
27 | @FunctionalInterface
28 | public interface ContextualSupplier {
29 | T get(ExecutionContext context) throws Throwable;
30 | }
31 |
--------------------------------------------------------------------------------
/core/src/main/java/dev/failsafe/function/package-info.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Functional interface types.
3 | */
4 | package dev.failsafe.function;
5 |
--------------------------------------------------------------------------------
/core/src/main/java/dev/failsafe/internal/CircuitBreakerExecutor.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2018 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License
15 | */
16 | package dev.failsafe.internal;
17 |
18 | import dev.failsafe.CircuitBreakerOpenException;
19 | import dev.failsafe.ExecutionContext;
20 | import dev.failsafe.spi.ExecutionResult;
21 | import dev.failsafe.spi.PolicyExecutor;
22 | import dev.failsafe.CircuitBreaker;
23 |
24 | /**
25 | * A PolicyExecutor that handles failures according to a {@link CircuitBreaker}.
26 | *
27 | * @param result type
28 | * @author Jonathan Halterman
29 | */
30 | public class CircuitBreakerExecutor extends PolicyExecutor {
31 | private final CircuitBreakerImpl circuitBreaker;
32 |
33 | public CircuitBreakerExecutor(CircuitBreakerImpl circuitBreaker, int policyIndex) {
34 | super(circuitBreaker, policyIndex);
35 | this.circuitBreaker = circuitBreaker;
36 | }
37 |
38 | @Override
39 | protected ExecutionResult preExecute() {
40 | return circuitBreaker.tryAcquirePermit() ?
41 | null :
42 | ExecutionResult.exception(new CircuitBreakerOpenException(circuitBreaker));
43 | }
44 |
45 | @Override
46 | public void onSuccess(ExecutionResult result) {
47 | circuitBreaker.recordSuccess();
48 | }
49 |
50 | @Override
51 | protected ExecutionResult onFailure(ExecutionContext context, ExecutionResult result) {
52 | circuitBreaker.recordExecutionFailure(context);
53 | return result;
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/core/src/main/java/dev/failsafe/internal/CircuitState.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2016 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License
15 | */
16 | package dev.failsafe.internal;
17 |
18 | import dev.failsafe.CircuitBreaker.State;
19 | import dev.failsafe.CircuitBreakerConfig;
20 | import dev.failsafe.CircuitBreakerOpenException;
21 | import dev.failsafe.ExecutionContext;
22 |
23 | import java.time.Duration;
24 |
25 | /**
26 | * The state of a circuit.
27 | *
28 | * @param result type
29 | * @author Jonathan Halterman
30 | */
31 | abstract class CircuitState {
32 | final CircuitBreakerImpl breaker;
33 | final CircuitBreakerConfig config;
34 | volatile CircuitStats stats;
35 |
36 | CircuitState(CircuitBreakerImpl breaker, CircuitStats stats) {
37 | this.breaker = breaker;
38 | this.config = breaker.getConfig();
39 | this.stats = stats;
40 | }
41 |
42 | public Duration getRemainingDelay() {
43 | return Duration.ZERO;
44 | }
45 |
46 | public CircuitStats getStats() {
47 | return stats;
48 | }
49 |
50 | public abstract State getState();
51 |
52 | public synchronized void recordFailure(ExecutionContext context) {
53 | stats.recordFailure();
54 | checkThreshold(context);
55 | releasePermit();
56 | }
57 |
58 | public synchronized void recordSuccess() {
59 | stats.recordSuccess();
60 | checkThreshold(null);
61 | releasePermit();
62 | }
63 |
64 | public void handleConfigChange() {
65 | }
66 |
67 | void checkThreshold(ExecutionContext context) {
68 | }
69 |
70 | abstract boolean tryAcquirePermit();
71 |
72 | void releasePermit() {
73 | }
74 | }
--------------------------------------------------------------------------------
/core/src/main/java/dev/failsafe/internal/CircuitStats.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2018 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License
15 | */
16 | package dev.failsafe.internal;
17 |
18 | import dev.failsafe.CircuitBreaker;
19 | import dev.failsafe.internal.TimedCircuitStats.Clock;
20 |
21 | /**
22 | * Stats for a circuit breaker.
23 | */
24 | interface CircuitStats {
25 | static CircuitStats create(CircuitBreaker> breaker, int capacity, boolean supportsTimeBased,
26 | CircuitStats oldStats) {
27 | if (supportsTimeBased && breaker.getConfig().getFailureThresholdingPeriod() != null)
28 | return new TimedCircuitStats(TimedCircuitStats.DEFAULT_BUCKET_COUNT,
29 | breaker.getConfig().getFailureThresholdingPeriod(), new Clock(), oldStats);
30 | else if (capacity > 1) {
31 | return new CountingCircuitStats(capacity, oldStats);
32 | } else {
33 | return new DefaultCircuitStats();
34 | }
35 | }
36 |
37 | default void copyExecutions(CircuitStats oldStats) {
38 | for (int i = 0; i < oldStats.getSuccessCount(); i++)
39 | recordSuccess();
40 | for (int i = 0; i < oldStats.getFailureCount(); i++)
41 | recordFailure();
42 | }
43 |
44 | int getFailureCount();
45 |
46 | int getExecutionCount();
47 |
48 | int getSuccessCount();
49 |
50 | int getFailureRate();
51 |
52 | int getSuccessRate();
53 |
54 | void recordFailure();
55 |
56 | void recordSuccess();
57 |
58 | void reset();
59 | }
60 |
--------------------------------------------------------------------------------
/core/src/main/java/dev/failsafe/internal/ClosedState.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2016 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License
15 | */
16 | package dev.failsafe.internal;
17 |
18 | import dev.failsafe.CircuitBreaker;
19 | import dev.failsafe.CircuitBreaker.State;
20 | import dev.failsafe.ExecutionContext;
21 |
22 | class ClosedState extends CircuitState {
23 | public ClosedState(CircuitBreakerImpl breaker) {
24 | super(breaker, CircuitStats.create(breaker, capacityFor(breaker), true, null));
25 | }
26 |
27 | @Override
28 | public boolean tryAcquirePermit() {
29 | return true;
30 | }
31 |
32 | @Override
33 | public State getState() {
34 | return State.CLOSED;
35 | }
36 |
37 | @Override
38 | public synchronized void handleConfigChange() {
39 | stats = CircuitStats.create(breaker, capacityFor(breaker), true, stats);
40 | }
41 |
42 | /**
43 | * Checks to see if the executions and failure thresholds have been exceeded, opening the circuit if so.
44 | */
45 | @Override
46 | synchronized void checkThreshold(ExecutionContext context) {
47 | // Execution threshold can only be set for time based thresholding
48 | if (stats.getExecutionCount() >= config.getFailureExecutionThreshold()) {
49 | // Failure rate threshold can only be set for time based thresholding
50 | double failureRateThreshold = config.getFailureRateThreshold();
51 | if ((failureRateThreshold != 0 && stats.getFailureRate() >= failureRateThreshold) || (failureRateThreshold == 0
52 | && stats.getFailureCount() >= config.getFailureThreshold()))
53 | breaker.open(context);
54 | }
55 | }
56 |
57 | /**
58 | * Returns the capacity of the breaker in the closed state.
59 | */
60 | private static int capacityFor(CircuitBreaker> breaker) {
61 | if (breaker.getConfig().getFailureExecutionThreshold() != 0)
62 | return breaker.getConfig().getFailureExecutionThreshold();
63 | else
64 | return breaker.getConfig().getFailureThresholdingCapacity();
65 | }
66 | }
--------------------------------------------------------------------------------
/core/src/main/java/dev/failsafe/internal/DefaultCircuitStats.java:
--------------------------------------------------------------------------------
1 | package dev.failsafe.internal;
2 |
3 | /**
4 | * A default CircuitStats implementation that tracks a single execution result.
5 | */
6 | class DefaultCircuitStats implements CircuitStats {
7 | volatile int result = -1;
8 |
9 | @Override
10 | public int getFailureCount() {
11 | return result == 0 ? 1 : 0;
12 | }
13 |
14 | @Override
15 | public int getExecutionCount() {
16 | return result == -1 ? 0 : 1;
17 | }
18 |
19 | @Override
20 | public int getSuccessCount() {
21 | return result == 1 ? 1 : 0;
22 | }
23 |
24 | @Override
25 | public int getFailureRate() {
26 | return getFailureCount() * 100;
27 | }
28 |
29 | @Override
30 | public int getSuccessRate() {
31 | return getSuccessCount() * 100;
32 | }
33 |
34 | @Override
35 | public void recordFailure() {
36 | result = 0;
37 | }
38 |
39 | @Override
40 | public void recordSuccess() {
41 | result = 1;
42 | }
43 |
44 | @Override
45 | public void reset() {
46 | result = -1;
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/core/src/main/java/dev/failsafe/internal/EventHandler.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2018 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License
15 | */
16 | package dev.failsafe.internal;
17 |
18 | import dev.failsafe.event.EventListener;
19 | import dev.failsafe.ExecutionContext;
20 | import dev.failsafe.event.ExecutionAttemptedEvent;
21 | import dev.failsafe.event.ExecutionCompletedEvent;
22 | import dev.failsafe.event.ExecutionScheduledEvent;
23 | import dev.failsafe.spi.ExecutionResult;
24 |
25 | import java.time.Duration;
26 |
27 | /**
28 | * Internal handling of events.
29 | *
30 | * @param result type
31 | */
32 | public interface EventHandler {
33 | void handle(ExecutionResult result, ExecutionContext context);
34 |
35 | static EventHandler ofExecutionCompleted(EventListener> handler) {
36 | return handler == null ?
37 | null :
38 | (result, context) -> handler.acceptUnchecked(
39 | new ExecutionCompletedEvent<>(result.getResult(), result.getException(), context));
40 | }
41 |
42 | static EventHandler ofExecutionAttempted(EventListener> handler) {
43 | return handler == null ?
44 | null :
45 | (result, context) -> handler.acceptUnchecked(
46 | new ExecutionAttemptedEvent<>(result.getResult(), result.getException(), context));
47 | }
48 |
49 | static EventHandler ofExecutionScheduled(EventListener> handler) {
50 | return handler == null ?
51 | null :
52 | (result, context) -> handler.acceptUnchecked(
53 | new ExecutionScheduledEvent<>(result.getResult(), result.getException(), Duration.ofNanos(result.getDelay()),
54 | context));
55 | }
56 | }
--------------------------------------------------------------------------------
/core/src/main/java/dev/failsafe/internal/FallbackImpl.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2016 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License
15 | */
16 | package dev.failsafe.internal;
17 |
18 | import dev.failsafe.Fallback;
19 | import dev.failsafe.event.ExecutionAttemptedEvent;
20 | import dev.failsafe.spi.FailurePolicy;
21 | import dev.failsafe.ExecutionContext;
22 | import dev.failsafe.FallbackBuilder;
23 | import dev.failsafe.FallbackConfig;
24 | import dev.failsafe.spi.PolicyExecutor;
25 |
26 | import java.util.concurrent.CompletableFuture;
27 |
28 | /**
29 | * A {@link Fallback} implementation.
30 | *
31 | * @param result type
32 | * @author Jonathan Halterman
33 | * @see FallbackBuilder
34 | */
35 | public class FallbackImpl implements Fallback, FailurePolicy {
36 | /**
37 | * A fallback that will return null if execution fails.
38 | */
39 | public static Fallback NONE = Fallback.builder(() -> null).build();
40 |
41 | private final FallbackConfig config;
42 |
43 | public FallbackImpl(FallbackConfig config) {
44 | this.config = config;
45 | }
46 |
47 | @Override
48 | public FallbackConfig getConfig() {
49 | return config;
50 | }
51 |
52 | /**
53 | * Returns the applied fallback result.
54 | */
55 | protected R apply(R result, Throwable exception, ExecutionContext context) throws Throwable {
56 | ExecutionAttemptedEvent event = new ExecutionAttemptedEvent<>(result, exception, context);
57 | return config.getFallback() != null ?
58 | config.getFallback().apply(event) :
59 | config.getFallbackStage().apply(event).get();
60 | }
61 |
62 | /**
63 | * Returns a future applied fallback result.
64 | */
65 | protected CompletableFuture applyStage(R result, Throwable exception, ExecutionContext context) throws Throwable {
66 | ExecutionAttemptedEvent event = new ExecutionAttemptedEvent<>(result, exception, context);
67 | return config.getFallback() != null ?
68 | CompletableFuture.completedFuture(config.getFallback().apply(event)) :
69 | config.getFallbackStage().apply(event);
70 | }
71 |
72 | @Override
73 | public PolicyExecutor toExecutor(int policyIndex) {
74 | return new FallbackExecutor<>(this, policyIndex);
75 | }
76 | }
77 |
--------------------------------------------------------------------------------
/core/src/main/java/dev/failsafe/internal/OpenState.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2016 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License
15 | */
16 | package dev.failsafe.internal;
17 |
18 | import dev.failsafe.CircuitBreaker.State;
19 |
20 | import java.time.Duration;
21 |
22 | class OpenState extends CircuitState {
23 | private final long startTime = System.nanoTime();
24 | private final long delayNanos;
25 |
26 | public OpenState(CircuitBreakerImpl breaker, CircuitState previousState, Duration delay) {
27 | super(breaker, previousState.stats);
28 | this.delayNanos = delay.toNanos();
29 | }
30 |
31 | @Override
32 | public boolean tryAcquirePermit() {
33 | if (System.nanoTime() - startTime >= delayNanos) {
34 | breaker.halfOpen();
35 | return breaker.tryAcquirePermit();
36 | }
37 |
38 | return false;
39 | }
40 |
41 | @Override
42 | public Duration getRemainingDelay() {
43 | long elapsedTime = System.nanoTime() - startTime;
44 | long remainingDelay = delayNanos - elapsedTime;
45 | return Duration.ofNanos(Math.max(remainingDelay, 0));
46 | }
47 |
48 | @Override
49 | public State getState() {
50 | return State.OPEN;
51 | }
52 | }
--------------------------------------------------------------------------------
/core/src/main/java/dev/failsafe/internal/RateLimiterStats.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2021 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License
15 | */
16 | package dev.failsafe.internal;
17 |
18 | import java.time.Duration;
19 |
20 | abstract class RateLimiterStats {
21 | final Stopwatch stopwatch;
22 |
23 | RateLimiterStats(Stopwatch stopwatch) {
24 | this.stopwatch = stopwatch;
25 | }
26 |
27 | static class Stopwatch {
28 | private long startTime = System.nanoTime();
29 |
30 | long elapsedNanos() {
31 | return System.nanoTime() - startTime;
32 | }
33 |
34 | void reset() {
35 | startTime = System.nanoTime();
36 | }
37 | }
38 |
39 | /**
40 | * Eagerly acquires permits and returns the time in nanos that must be waited in order to use the permits, else
41 | * returns {@code -1} if the wait time would exceed the {@code maxWaitTime}.
42 | *
43 | * @param permits the number of requested permits
44 | * @param maxWaitTime the max time to wait for the requested permits, else {@code null} to wait indefinitely
45 | */
46 | abstract long acquirePermits(long permits, Duration maxWaitTime);
47 |
48 | /**
49 | * Returns whether the {@code waitNanos} would exceed the {@code maxWaitTime}, else {@code false} if {@code
50 | * maxWaitTime} is null.
51 | */
52 | boolean exceedsMaxWaitTime(long waitNanos, Duration maxWaitTime) {
53 | return maxWaitTime != null && waitNanos > maxWaitTime.toNanos();
54 | }
55 |
56 | /**
57 | * Returns the elapsed time since the rate limiter began.
58 | */
59 | Duration getElapsed() {
60 | return Duration.ofNanos(stopwatch.elapsedNanos());
61 | }
62 |
63 | /**
64 | * Resets the rate limiter's internal stats.
65 | */
66 | abstract void reset();
67 | }
--------------------------------------------------------------------------------
/core/src/main/java/dev/failsafe/internal/RetryPolicyImpl.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2016 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License
15 | */
16 | package dev.failsafe.internal;
17 |
18 | import dev.failsafe.RetryPolicy;
19 | import dev.failsafe.RetryPolicyBuilder;
20 | import dev.failsafe.RetryPolicyConfig;
21 | import dev.failsafe.function.CheckedBiPredicate;
22 | import dev.failsafe.function.CheckedPredicate;
23 | import dev.failsafe.spi.DelayablePolicy;
24 | import dev.failsafe.spi.FailurePolicy;
25 | import dev.failsafe.spi.PolicyExecutor;
26 |
27 | import java.util.List;
28 |
29 | /**
30 | * A {@link RetryPolicy} implementation.
31 | *
32 | * @param result type
33 | * @author Jonathan Halterman
34 | * @see RetryPolicyBuilder
35 | */
36 | public class RetryPolicyImpl implements RetryPolicy, FailurePolicy, DelayablePolicy {
37 | private final RetryPolicyConfig config;
38 |
39 | public RetryPolicyImpl(RetryPolicyConfig config) {
40 | this.config = config;
41 | }
42 |
43 | @Override
44 | public RetryPolicyConfig getConfig() {
45 | return config;
46 | }
47 |
48 | /**
49 | * Returns whether an execution result can be aborted given the configured abort conditions.
50 | *
51 | * @see RetryPolicyBuilder#abortOn(Class...)
52 | * @see RetryPolicyBuilder#abortOn(List)
53 | * @see RetryPolicyBuilder#abortOn(CheckedPredicate)
54 | * @see RetryPolicyBuilder#abortIf(CheckedBiPredicate)
55 | * @see RetryPolicyBuilder#abortIf(CheckedPredicate)
56 | * @see RetryPolicyBuilder#abortWhen(R)
57 | */
58 | public boolean isAbortable(R result, Throwable failure) {
59 | for (CheckedBiPredicate predicate : config.getAbortConditions()) {
60 | try {
61 | if (predicate.test(result, failure))
62 | return true;
63 | } catch (Throwable ignore) {
64 | }
65 | }
66 | return false;
67 | }
68 |
69 | @Override
70 | public PolicyExecutor toExecutor(int policyIndex) {
71 | return new RetryPolicyExecutor<>(this, policyIndex);
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/core/src/main/java/dev/failsafe/internal/SmoothRateLimiterStats.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2021 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License
15 | */
16 | package dev.failsafe.internal;
17 |
18 | import dev.failsafe.RateLimiterConfig;
19 | import dev.failsafe.internal.util.Maths;
20 |
21 | import java.time.Duration;
22 |
23 | /**
24 | * A rate limiter implementation that evenly distributes permits over time, based on the max permits per period. This
25 | * implementation focuses on the interval between permits, and tracks the next interval in which a permit is free.
26 | */
27 | class SmoothRateLimiterStats extends RateLimiterStats {
28 | /* The nanos per interval between permits */
29 | final long intervalNanos;
30 |
31 | // The amount of time, relative to the start time, that the next permit will be free.
32 | // Will be a multiple of intervalNanos.
33 | private long nextFreePermitNanos;
34 |
35 | SmoothRateLimiterStats(RateLimiterConfig> config, Stopwatch stopwatch) {
36 | super(stopwatch);
37 | intervalNanos = config.getMaxRate().toNanos();
38 | }
39 |
40 | @Override
41 | public synchronized long acquirePermits(long requestedPermits, Duration maxWaitTime) {
42 | long currentNanos = stopwatch.elapsedNanos();
43 | long requestedPermitNanos = requestedPermits * intervalNanos;
44 | long waitNanos;
45 | long newNextFreePermitNanos;
46 |
47 | // If a permit is currently available
48 | if (currentNanos >= nextFreePermitNanos) {
49 | // Nanos at the start of the current interval
50 | long currentIntervalNanos = Maths.roundDown(currentNanos, intervalNanos);
51 | newNextFreePermitNanos = Maths.add(currentIntervalNanos, requestedPermitNanos);
52 | } else {
53 | newNextFreePermitNanos = Maths.add(nextFreePermitNanos, requestedPermitNanos);
54 | }
55 |
56 | waitNanos = Math.max(newNextFreePermitNanos - currentNanos - intervalNanos, 0);
57 |
58 | if (exceedsMaxWaitTime(waitNanos, maxWaitTime))
59 | return -1;
60 |
61 | nextFreePermitNanos = newNextFreePermitNanos;
62 | return waitNanos;
63 | }
64 |
65 | synchronized long getNextFreePermitNanos() {
66 | return nextFreePermitNanos;
67 | }
68 |
69 | @Override
70 | synchronized void reset() {
71 | stopwatch.reset();
72 | nextFreePermitNanos = 0;
73 | }
74 | }
--------------------------------------------------------------------------------
/core/src/main/java/dev/failsafe/internal/TimeoutImpl.java:
--------------------------------------------------------------------------------
1 | package dev.failsafe.internal;
2 |
3 | import dev.failsafe.Timeout;
4 | import dev.failsafe.TimeoutBuilder;
5 | import dev.failsafe.TimeoutConfig;
6 | import dev.failsafe.TimeoutExceededException;
7 | import dev.failsafe.spi.PolicyExecutor;
8 |
9 | /**
10 | * A {@link Timeout} implementation.
11 | *
12 | * @param result type
13 | * @author Jonathan Halterman
14 | * @see TimeoutBuilder
15 | * @see TimeoutExceededException
16 | */
17 | public class TimeoutImpl implements Timeout {
18 | private final TimeoutConfig config;
19 |
20 | public TimeoutImpl(TimeoutConfig config) {
21 | this.config = config;
22 | }
23 |
24 | @Override
25 | public TimeoutConfig getConfig() {
26 | return config;
27 | }
28 |
29 | @Override
30 | public PolicyExecutor toExecutor(int policyIndex) {
31 | return new TimeoutExecutor<>(this, policyIndex);
32 | }
33 |
34 | @Override
35 | public String toString() {
36 | return "Timeout[timeout=" + config.getTimeout() + ", interruptable=" + config.canInterrupt() + ']';
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/core/src/main/java/dev/failsafe/internal/util/Assert.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2016 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License
15 | */
16 | package dev.failsafe.internal.util;
17 |
18 | /**
19 | * Assertion utilities.
20 | *
21 | * @author Jonathan Halterman
22 | */
23 | public final class Assert {
24 | private Assert() {
25 | }
26 |
27 | public static void isTrue(boolean expression, String errorMessageFormat, Object... args) {
28 | if (!expression)
29 | throw new IllegalArgumentException(String.format(errorMessageFormat, args));
30 | }
31 |
32 | public static T notNull(T reference, String parameterName) {
33 | if (reference == null)
34 | throw new NullPointerException(parameterName + " cannot be null");
35 | return reference;
36 | }
37 |
38 | public static void state(boolean expression, String errorMessageFormat, Object... args) {
39 | if (!expression)
40 | throw new IllegalStateException(String.format(errorMessageFormat, args));
41 | }
42 | }
--------------------------------------------------------------------------------
/core/src/main/java/dev/failsafe/internal/util/Durations.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011-2021 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License
15 | */
16 | package dev.failsafe.internal.util;
17 |
18 | import java.time.Duration;
19 |
20 | /**
21 | * Duration and long utilities.
22 | */
23 | public final class Durations {
24 | static long MAX_SECONDS_PER_LONG = Long.MAX_VALUE / 1000_000_000L;
25 | static Duration MAX_SAFE_NANOS_DURATION = Duration.ofSeconds(MAX_SECONDS_PER_LONG);
26 |
27 | private Durations() {
28 | }
29 |
30 | /**
31 | * Returns either the {@code duration} else a Duration containing the max seconds that can safely be converted to
32 | * nanos without overflowing.
33 | */
34 | public static Duration ofSafeNanos(Duration duration) {
35 | return duration.getSeconds() < MAX_SECONDS_PER_LONG ? duration : MAX_SAFE_NANOS_DURATION;
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/core/src/main/java/dev/failsafe/internal/util/FutureLinkedList.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2022 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License
15 | */
16 | package dev.failsafe.internal.util;
17 |
18 | import java.util.concurrent.CompletableFuture;
19 |
20 | /**
21 | * A LinkedList of CompletableFutures that removes a future from the list when it's completed.
22 | *
23 | * This class is threadsafe.
24 | *
25 | *
26 | * @author Jonathan Halterman
27 | */
28 | public final class FutureLinkedList {
29 | Node head;
30 | Node tail;
31 |
32 | static class Node {
33 | Node previous;
34 | Node next;
35 | CompletableFuture future;
36 | }
37 |
38 | /**
39 | * Adds a new CompletableFuture to the list and returns it. The returned future will be removed from the list when
40 | * it's completed.
41 | */
42 | public synchronized CompletableFuture add() {
43 | Node node = new Node();
44 | node.future = new CompletableFuture<>();
45 | node.future.whenComplete((result, error) -> remove(node));
46 |
47 | if (head == null)
48 | head = tail = node;
49 | else {
50 | tail.next = node;
51 | node.previous = tail;
52 | tail = node;
53 | }
54 | return node.future;
55 | }
56 |
57 | /**
58 | * Returns and removes the first future in the list, else returns {@code null} if the list is empty.
59 | */
60 | public synchronized CompletableFuture pollFirst() {
61 | Node previousHead = head;
62 | if (head != null) {
63 | head = head.next;
64 | if (head != null)
65 | head.previous = null;
66 | }
67 | return previousHead == null ? null : previousHead.future;
68 | }
69 |
70 | private synchronized void remove(Node node) {
71 | if (node.previous != null)
72 | node.previous.next = node.next;
73 | if (node.next != null)
74 | node.next.previous = node.previous;
75 | if (head == node)
76 | head = node.next;
77 | if (tail == node)
78 | tail = node.previous;
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/core/src/main/java/dev/failsafe/internal/util/Lists.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011-2021 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License
15 | */
16 | package dev.failsafe.internal.util;
17 |
18 | import java.util.ArrayList;
19 | import java.util.Collections;
20 | import java.util.List;
21 |
22 | /**
23 | * List utilities.
24 | *
25 | * @author Jonathan Halterman
26 | */
27 | public final class Lists {
28 | private Lists() {
29 | }
30 |
31 | /**
32 | * Returns a list containing the {@code first} element followed by the {@code rest}.
33 | */
34 | public static List of(T first, T[] rest) {
35 | List result = new ArrayList<>(rest.length + 1);
36 | result.add(first);
37 | Collections.addAll(result, rest);
38 | return result;
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/core/src/main/java/dev/failsafe/internal/util/Maths.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011-2021 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License
15 | */
16 | package dev.failsafe.internal.util;
17 |
18 | /**
19 | * Misc math utilities.
20 | */
21 | public final class Maths {
22 | private Maths() {
23 | }
24 |
25 | /**
26 | * Returns the sum of {@code a} and {@code b} else {@code Long.MAX_VALUE} if the sum would otherwise overflow.
27 | */
28 | public static long add(long a, long b) {
29 | long naiveSum = a + b;
30 | return (a ^ b) < 0L | (a ^ naiveSum) >= 0L ? naiveSum : 9223372036854775807L + (naiveSum >>> 63 ^ 1L);
31 | }
32 |
33 | /**
34 | * Returns the {@code input} rounded down to the nearest {@code interval}.
35 | */
36 | public static long roundDown(long input, long interval) {
37 | return (input / interval) * interval;
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/core/src/main/java/dev/failsafe/internal/util/RandomDelay.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2018 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License
15 | */
16 | package dev.failsafe.internal.util;
17 |
18 | /**
19 | * Utilities for computing random delays.
20 | *
21 | * @author Jonathan Halterman
22 | */
23 | public final class RandomDelay {
24 | private RandomDelay() {
25 | }
26 |
27 | public static long randomDelayInRange(long delayMin, long delayMax, double random) {
28 | return (long) (random * (delayMax - delayMin)) + delayMin;
29 | }
30 |
31 | public static long randomDelay(long delay, long jitter, double random) {
32 | double randomAddend = (1 - random * 2) * jitter;
33 | return (long) (delay + randomAddend);
34 | }
35 |
36 | public static long randomDelay(long delay, double jitterFactor, double random) {
37 | double randomFactor = 1 + (1 - random * 2) * jitterFactor;
38 | return (long) (delay * randomFactor);
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/core/src/main/java/dev/failsafe/package-info.java:
--------------------------------------------------------------------------------
1 | /**
2 | * APIs for performing failsafe executions.
3 | *
4 | * {@link dev.failsafe.Failsafe} is the entry point for the library. See {@link dev.failsafe.FailsafeExecutor}
5 | * for execution options.
6 | */
7 | package dev.failsafe;
8 |
--------------------------------------------------------------------------------
/core/src/main/java/dev/failsafe/spi/AsyncExecutionInternal.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2018 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License
15 | */
16 | package dev.failsafe.spi;
17 |
18 | import dev.failsafe.AsyncExecution;
19 |
20 | /**
21 | * Internal async execution APIs.
22 | *
23 | * @param result type
24 | * @author Jonathan Halterman
25 | */
26 | public interface AsyncExecutionInternal extends ExecutionInternal, AsyncExecution {
27 | /**
28 | * Returns whether the execution is an async integration execution.
29 | */
30 | boolean isAsyncExecution();
31 |
32 | /**
33 | * Returns whether one of the public {@link AsyncExecution} record or complete methods have been called.
34 | */
35 | boolean isRecorded();
36 |
37 | /**
38 | * Sets the PolicyExecutor corresponding to the {@code policyIndex} as having post-executed.
39 | */
40 | void setPostExecuted(int policyIndex);
41 |
42 | /**
43 | * Returns whether the PolicyExecutor corresponding to the {@code policyIndex} has already post-executed.
44 | */
45 | boolean isPostExecuted(int policyIndex);
46 |
47 | /**
48 | * Returns a new copy of the AsyncExecutionInternal.
49 | */
50 | AsyncExecutionInternal copy();
51 | }
52 |
--------------------------------------------------------------------------------
/core/src/main/java/dev/failsafe/spi/DefaultScheduledFuture.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2016 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License
15 | */
16 | package dev.failsafe.spi;
17 |
18 | import java.util.concurrent.Delayed;
19 | import java.util.concurrent.ExecutionException;
20 | import java.util.concurrent.ScheduledFuture;
21 | import java.util.concurrent.TimeUnit;
22 | import java.util.concurrent.TimeoutException;
23 |
24 | /**
25 | * A default ScheduledFuture implementation. Useful for {@link Scheduler} implementations.
26 | *
27 | * @param result type
28 | * @author Jonathan Halterman
29 | */
30 | public class DefaultScheduledFuture implements ScheduledFuture {
31 | /**
32 | * @return {@code 0}
33 | */
34 | @Override
35 | public long getDelay(TimeUnit unit) {
36 | return 0;
37 | }
38 |
39 | /**
40 | * @return {@code 0}
41 | */
42 | @Override
43 | public int compareTo(Delayed o) {
44 | return 0;
45 | }
46 |
47 | /**
48 | * @return {@code false}
49 | */
50 | @Override
51 | public boolean cancel(boolean mayInterruptIfRunning) {
52 | return false;
53 | }
54 |
55 | /**
56 | * @return {@code false}
57 | */
58 | @Override
59 | public boolean isCancelled() {
60 | return false;
61 | }
62 |
63 | /**
64 | * @return {@code false}
65 | */
66 | @Override
67 | public boolean isDone() {
68 | return false;
69 | }
70 |
71 | /**
72 | * @return {@code null}
73 | */
74 | @Override
75 | public R get() throws InterruptedException, ExecutionException {
76 | return null;
77 | }
78 |
79 | /**
80 | * @return {@code null}
81 | */
82 | @Override
83 | public R get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
84 | return null;
85 | }
86 | }
--------------------------------------------------------------------------------
/core/src/main/java/dev/failsafe/spi/DelayablePolicy.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2018 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License
15 | */
16 | package dev.failsafe.spi;
17 |
18 | import dev.failsafe.DelayablePolicyConfig;
19 | import dev.failsafe.ExecutionContext;
20 | import dev.failsafe.Policy;
21 | import dev.failsafe.internal.util.Durations;
22 |
23 | import java.time.Duration;
24 |
25 | /**
26 | * A policy that can be delayed between executions.
27 | *
28 | * @param result type
29 | * @author Jonathan Halterman
30 | */
31 | public interface DelayablePolicy extends Policy {
32 | DelayablePolicyConfig getConfig();
33 |
34 | /**
35 | * Returns a computed delay for the {@code result} and {@code context} else {@code null} if no delay function is
36 | * configured or the computed delay is invalid.
37 | */
38 | default Duration computeDelay(ExecutionContext context) {
39 | DelayablePolicyConfig config = getConfig();
40 | Duration computed = null;
41 | if (context != null && config.getDelayFn() != null) {
42 | R result = context.getLastResult();
43 | Throwable exception = context.getLastException();
44 |
45 | R delayResult = config.getDelayResult();
46 | Class extends Throwable> delayFailure = config.getDelayException();
47 | boolean delayResultMatched = delayResult == null || delayResult.equals(result);
48 | boolean delayExceptionMatched =
49 | delayFailure == null || (exception != null && delayFailure.isAssignableFrom(exception.getClass()));
50 | if (delayResultMatched && delayExceptionMatched) {
51 | try {
52 | computed = Durations.ofSafeNanos(config.getDelayFn().get(context));
53 | } catch (Throwable e) {
54 | if (e instanceof RuntimeException)
55 | throw (RuntimeException) e;
56 | else
57 | throw new RuntimeException(e);
58 | }
59 | }
60 | }
61 |
62 | return computed != null && !computed.isNegative() ? computed : null;
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/core/src/main/java/dev/failsafe/spi/ExecutionInternal.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2018 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License
15 | */
16 | package dev.failsafe.spi;
17 |
18 | import dev.failsafe.ExecutionContext;
19 |
20 | /**
21 | * Internal execution APIs.
22 | *
23 | * @param result type
24 | * @author Jonathan Halterman
25 | */
26 | public interface ExecutionInternal extends ExecutionContext {
27 | /**
28 | * Returns the recorded result for an execution attempt.
29 | */
30 | ExecutionResult getResult();
31 |
32 | /**
33 | * Called when execution of the user's supplier is about to begin.
34 | */
35 | void preExecute();
36 |
37 | /**
38 | * Returns whether the execution has been pre-executed, indicating the attempt has started.
39 | */
40 | boolean isPreExecuted();
41 |
42 | /**
43 | * Records an execution attempt which may correspond with an execution result. Async executions will have results
44 | * recorded separately.
45 | */
46 | void recordAttempt();
47 |
48 | /**
49 | * Records the {@code result} if the execution has been {@link #preExecute() pre-executed} and a result has not
50 | * already been recorded.
51 | */
52 | void record(ExecutionResult result);
53 |
54 | /**
55 | * Marks the execution as having been cancelled externally, which will cancel pending executions of all policies.
56 | *
57 | * @return whether cancellation was successful or not. Returns {@code false} if the execution was already cancelled or
58 | * completed.
59 | */
60 | boolean cancel();
61 |
62 | /**
63 | * Marks the execution as having been cancelled by the {@code policyExecutor}, which will also cancel pending
64 | * executions of any inner policies of the {@code policyExecutor}. Outer policies of the {@code policyExecutor} will
65 | * be unaffected.
66 | */
67 | void cancel(PolicyExecutor policyExecutor);
68 |
69 | /**
70 | * Returns whether the execution is considered cancelled for the {@code policyExecutor}.
71 | */
72 | boolean isCancelled(PolicyExecutor policyExecutor);
73 |
74 | /**
75 | * Returns a lock object that is common across all execution attempts. Useful for guarding against races when mutating
76 | * an execution.
77 | */
78 | Object getLock();
79 |
80 | /**
81 | * Returns the most recent execution to be attempted.
82 | */
83 | ExecutionInternal getLatest();
84 | }
85 |
--------------------------------------------------------------------------------
/core/src/main/java/dev/failsafe/spi/FailurePolicy.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2018 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License
15 | */
16 | package dev.failsafe.spi;
17 |
18 | import dev.failsafe.FailurePolicyBuilder;
19 | import dev.failsafe.FailurePolicyConfig;
20 | import dev.failsafe.Policy;
21 | import dev.failsafe.function.CheckedBiPredicate;
22 | import dev.failsafe.function.CheckedPredicate;
23 |
24 | import java.util.List;
25 |
26 | /**
27 | * A policy that can handle specifically configured failures.
28 | *
29 | * @param result type
30 | * @author Jonathan Halterman
31 | */
32 | public interface FailurePolicy extends Policy {
33 | FailurePolicyConfig getConfig();
34 |
35 | /**
36 | * Returns whether an execution {@code result} or {@code exception} are considered a failure according to the policy
37 | * configuration.
38 | *
39 | * @see FailurePolicyBuilder#handle(Class...)
40 | * @see FailurePolicyBuilder#handle(List)
41 | * @see FailurePolicyBuilder#handleIf(CheckedBiPredicate)
42 | * @see FailurePolicyBuilder#handleIf(CheckedPredicate)
43 | * @see FailurePolicyBuilder#handleResult(Object)
44 | * @see FailurePolicyBuilder#handleResultIf(CheckedPredicate)
45 | */
46 | default boolean isFailure(R result, Throwable exception) {
47 | FailurePolicyConfig config = getConfig();
48 | if (config.getFailureConditions().isEmpty())
49 | return exception != null;
50 |
51 | for (CheckedBiPredicate predicate : config.getFailureConditions()) {
52 | try {
53 | if (predicate.test(result, exception))
54 | return true;
55 | } catch (Throwable ignore) {
56 | }
57 | }
58 |
59 | // Fail by default if an exception is not checked by a condition
60 | return exception != null && !config.isExceptionsChecked();
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/core/src/main/java/dev/failsafe/spi/Scheduler.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2016 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License
15 | */
16 | package dev.failsafe.spi;
17 |
18 | import dev.failsafe.internal.util.DelegatingScheduler;
19 |
20 | import java.util.concurrent.*;
21 |
22 | /**
23 | * Schedules executions.
24 | *
25 | * @author Jonathan Halterman
26 | * @see DefaultScheduledFuture
27 | */
28 | public interface Scheduler {
29 | /**
30 | * The default scheduler used by Failsafe if no other scheduler or {@link ScheduledExecutorService} is configured for
31 | * an execution.
32 | */
33 | Scheduler DEFAULT = DelegatingScheduler.INSTANCE;
34 |
35 | /**
36 | * Schedules the {@code callable} to be called after the {@code delay} for the {@code unit}.
37 | */
38 | ScheduledFuture> schedule(Callable> callable, long delay, TimeUnit unit);
39 |
40 | /**
41 | * Returns a Scheduler adapted from the {@code scheduledExecutorService}.
42 | */
43 | static Scheduler of(ScheduledExecutorService scheduledExecutorService) {
44 | return scheduledExecutorService::schedule;
45 | }
46 |
47 | /**
48 | * Returns a Scheduler adapted from the {@code executorService}.
49 | */
50 | static Scheduler of(ExecutorService executorService) {
51 | return executorService instanceof ScheduledExecutorService ?
52 | of((ScheduledExecutorService) executorService) :
53 | new DelegatingScheduler(executorService);
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/core/src/main/java/dev/failsafe/spi/SyncExecutionInternal.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2018 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License
15 | */
16 | package dev.failsafe.spi;
17 |
18 | import dev.failsafe.Execution;
19 |
20 | /**
21 | * Internal execution APIs.
22 | *
23 | * @param result type
24 | * @author Jonathan Halterman
25 | */
26 | public interface SyncExecutionInternal extends ExecutionInternal, Execution {
27 | /**
28 | * Returns whether the execution is currently interrupted.
29 | */
30 | boolean isInterrupted();
31 |
32 | /**
33 | * Sets whether the execution is currently {@code interruptable}.
34 | */
35 | void setInterruptable(boolean interruptable);
36 |
37 | /**
38 | * Interrupts the execution.
39 | */
40 | void interrupt();
41 |
42 | /**
43 | * Returns a new copy of the SyncExecutionInternal if it is not standalone, else returns {@code this} since standalone
44 | * executions are referenced externally and cannot be replaced.
45 | */
46 | SyncExecutionInternal copy();
47 | }
48 |
--------------------------------------------------------------------------------
/core/src/main/java/dev/failsafe/spi/package-info.java:
--------------------------------------------------------------------------------
1 | /**
2 | * The Failsafe Service Provider Interface (SPI). These classes and interfaces allow Failsafe to be extended with new
3 | * policies.
4 | */
5 | package dev.failsafe.spi;
6 |
--------------------------------------------------------------------------------
/core/src/main/javadoc/overview.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | Failsafe - fault tolerance and resilience patterns for the JVM.
4 |
7 |
8 |
--------------------------------------------------------------------------------
/core/src/test/java/dev/failsafe/BulkheadBuilderTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2021 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License
15 | */
16 | package dev.failsafe;
17 |
18 | import org.testng.annotations.Test;
19 |
20 | import java.time.Duration;
21 |
22 | import static org.testng.Assert.*;
23 |
24 | @Test
25 | public class BulkheadBuilderTest {
26 | public void shouldCreateBuilderFromExistingConfig() {
27 | BulkheadConfig