├── docs ├── package-list ├── script.js ├── allclasses-noframe.html ├── allclasses-frame.html ├── com │ └── github │ │ └── rholder │ │ └── retry │ │ ├── package-frame.html │ │ ├── package-tree.html │ │ ├── WaitStrategy.html │ │ ├── StopStrategy.html │ │ ├── BlockStrategy.html │ │ ├── RetryListener.html │ │ ├── AttemptTimeLimiter.html │ │ ├── BlockStrategies.html │ │ ├── Retryer.RetryerCallable.html │ │ ├── package-summary.html │ │ └── RetryException.html ├── index.html ├── constant-values.html ├── deprecated-list.html ├── serialized-form.html ├── overview-tree.html └── help-doc.html ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── .gitignore ├── NOTICE ├── .travis.yml ├── src ├── main │ └── java │ │ └── com │ │ └── github │ │ └── rholder │ │ └── retry │ │ ├── WaitStrategy.java │ │ ├── StopStrategy.java │ │ ├── RetryListener.java │ │ ├── AttemptTimeLimiter.java │ │ ├── BlockStrategy.java │ │ ├── BlockStrategies.java │ │ ├── RetryException.java │ │ ├── Attempt.java │ │ ├── AttemptTimeLimiters.java │ │ ├── StopStrategies.java │ │ ├── Retryer.java │ │ └── RetryerBuilder.java └── test │ └── java │ └── com │ └── github │ └── rholder │ └── retry │ ├── AttemptTimeLimitersTest.java │ ├── AttemptTimeLimiterTest.java │ ├── StopStrategiesTest.java │ └── WaitStrategiesTest.java ├── HISTORY.md ├── gradlew.bat ├── gradlew └── README.md /docs/package-list: -------------------------------------------------------------------------------- 1 | com.github.rholder.retry 2 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rhuffman/re-retrying/HEAD/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .gradle 2 | .idea 3 | build 4 | out 5 | *.iml 6 | *.ipr 7 | *.iws 8 | fileTemplates 9 | gradle.properties 10 | .DS_Store 11 | classes/ 12 | gradle/.DS_STORE 13 | local.properties 14 | .attach_pid* 15 | .#* 16 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | zipStoreBase=GRADLE_USER_HOME 4 | zipStorePath=wrapper/dists 5 | distributionUrl=https\://services.gradle.org/distributions/gradle-4.8-bin.zip 6 | -------------------------------------------------------------------------------- /NOTICE: -------------------------------------------------------------------------------- 1 | Copyright 2012-2015 Ray Holder 2 | Modifications copyright 2017-2018 Robert Huffman 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 | -------------------------------------------------------------------------------- /docs/script.js: -------------------------------------------------------------------------------- 1 | function show(type) 2 | { 3 | count = 0; 4 | for (var key in methods) { 5 | var row = document.getElementById(key); 6 | if ((methods[key] & type) != 0) { 7 | row.style.display = ''; 8 | row.className = (count++ % 2) ? rowColor : altColor; 9 | } 10 | else 11 | row.style.display = 'none'; 12 | } 13 | updateTabs(type); 14 | } 15 | 16 | function updateTabs(type) 17 | { 18 | for (var value in tabs) { 19 | var sNode = document.getElementById(tabs[value][0]); 20 | var spanNode = sNode.firstChild; 21 | if (value == type) { 22 | sNode.className = activeTableTab; 23 | spanNode.innerHTML = tabs[value][1]; 24 | } 25 | else { 26 | sNode.className = tableTab; 27 | spanNode.innerHTML = "" + tabs[value][1] + ""; 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | # Copyright 2012-2015 Ray Holder 2 | # Modifications copyright 2017-2018 Robert Huffman 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 | sudo: false 17 | language: java 18 | jdk: 19 | - oraclejdk8 20 | - openjdk8 21 | 22 | # Avoid uploading the Gradle cache after every build 23 | # See https://docs.travis-ci.com/user/languages/java/#Caching 24 | before_cache: 25 | - rm -f $HOME/.gradle/caches/modules-2/modules-2.lock 26 | - rm -fr $HOME/.gradle/caches/*/plugin-resolution/ 27 | cache: 28 | directories: 29 | - $HOME/.gradle/caches/ 30 | - $HOME/.gradle/wrapper/ 31 | -------------------------------------------------------------------------------- /src/main/java/com/github/rholder/retry/WaitStrategy.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012-2015 Ray Holder 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 | 17 | package com.github.rholder.retry; 18 | 19 | /** 20 | * A strategy used to decide how long to sleep before retrying after a failed attempt. 21 | * 22 | * @author JB 23 | */ 24 | public interface WaitStrategy { 25 | 26 | /** 27 | * Returns the time, in milliseconds, to sleep before retrying. 28 | * 29 | * @param failedAttempt the previous failed {@code Attempt} 30 | * @return the sleep time before next attempt 31 | */ 32 | long computeSleepTime(Attempt failedAttempt); 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/com/github/rholder/retry/StopStrategy.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012-2015 Ray Holder 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 | 17 | package com.github.rholder.retry; 18 | 19 | /** 20 | * A strategy used to decide if a retryer must stop retrying after a failed attempt or not. 21 | * 22 | * @author JB 23 | */ 24 | public interface StopStrategy { 25 | 26 | /** 27 | * Returns true if the retryer should stop retrying. 28 | * 29 | * @param failedAttempt the previous failed {@code Attempt} 30 | * @return true if the retryer must stop, false otherwise 31 | */ 32 | boolean shouldStop(Attempt failedAttempt); 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/com/github/rholder/retry/RetryListener.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012-2015 Ray Holder 3 | * Modifications copyright 2017-2018 Robert Huffman 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package com.github.rholder.retry; 19 | 20 | import com.google.common.annotations.Beta; 21 | 22 | /** 23 | * This listener provides callbacks for several events that occur when running 24 | * code through a {@link Retryer} instance. 25 | */ 26 | @Beta 27 | public interface RetryListener { 28 | 29 | /** 30 | * This method with fire no matter what the result is and before the 31 | * retry predicate and stop strategies are applied. 32 | * 33 | * @param attempt the current {@link Attempt} 34 | */ 35 | void onRetry(Attempt attempt); 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/com/github/rholder/retry/AttemptTimeLimiter.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012-2015 Ray Holder 3 | * Modifications copyright 2017-2018 Robert Huffman 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package com.github.rholder.retry; 19 | 20 | import java.util.concurrent.Callable; 21 | 22 | /** 23 | * A rule to wrap any single attempt in a time limit, where it will possibly be interrupted if the limit is exceeded. 24 | * 25 | * @author Jason Dunkelberger (dirkraft) 26 | */ 27 | public interface AttemptTimeLimiter { 28 | /** 29 | * @param callable to subject to the time limit 30 | * @return the return of the given callable 31 | * @param The return type of the Callable's call method 32 | * @throws Exception any exception from this invocation 33 | */ 34 | T call(Callable callable) throws Exception; 35 | } 36 | -------------------------------------------------------------------------------- /HISTORY.md: -------------------------------------------------------------------------------- 1 | ##2.0.0 - 2015-06-30 2 | * Calculate sleep time from failed attempt #25 (yaroslavm) 3 | * Be consistent about "duration" method parameters #30 (Stephan202) 4 | * Use an open Maven dependency range for Guava dependency #32 (voiceinsideyou) 5 | * Add @Beta RetryListener support #36 (kevinconaway) 6 | * Update to Gradle 2.x #38 7 | * Minimal breaking 1.0.x to 2.0.x API changes for Attempt state, hence the major version update 8 | 9 | ##1.0.7 - 2015-01-20 10 | * New composite wait strategy #12 (shasts) 11 | * Adding block strategies to the Retryer to decide how to block (tchdp) 12 | 13 | ##1.0.6 - 2014-03-26 14 | * Javadoc updates for Java 8 (shasts) 15 | * Bug from System.nanoTime() (fror), fix in #15 16 | * Travis CI testing now working for Java 8 17 | 18 | ##1.0.5 - 2013-12-04 19 | * Added Javadoc for all versions 20 | * Added FibonacciWaitStrategy (joschi) 21 | * Updated tested Guava version range from 10.x.x - 15.0 (joschi) 22 | * Updated all dependencies (joschi) 23 | * Updated to Gradle 1.9 (joschi) 24 | 25 | ##1.0.4 - 2013-07-08 26 | * Added tested Guava version range from 10.x.x - 14.0.1 27 | * Added Exception cause propagation to RetryException to fix #3 28 | 29 | ##1.0.3 - 2013-01-16 30 | * Added time limit per attempt in a Retryer (dirkraft) 31 | * Added license text 32 | 33 | ##1.0.2 - 2012-11-22 34 | * Added Gradle wrapper support 35 | * Updated top-level package to com.github.rholder.retry 36 | 37 | ##1.0.1 - 2012-08-29 38 | * Added Javadoc links 39 | * Added exponential wait strategy and unit tests 40 | 41 | ##1.0.0 - 2012-08-26 42 | * Initial stable release, packaging for Maven central, no changes from original source 43 | -------------------------------------------------------------------------------- /src/main/java/com/github/rholder/retry/BlockStrategy.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012-2015 Ray Holder 3 | * Modifications copyright 2017-2018 Robert Huffman 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package com.github.rholder.retry; 19 | 20 | /** 21 | * This is a strategy used to decide how a retryer should block between retry 22 | * attempts. Normally this is just a Thread.sleep(), but implementations can be 23 | * something more elaborate if desired. 24 | */ 25 | public interface BlockStrategy { 26 | 27 | /** 28 | * Attempt to block for the designated amount of time. Implementations 29 | * that don't block or otherwise delay the processing from within this 30 | * method for the given sleep duration can significantly modify the behavior 31 | * of any configured {@link com.github.rholder.retry.WaitStrategy}. Caution 32 | * is advised when generating your own implementations. 33 | * 34 | * @param sleepTime the computed sleep duration in milliseconds 35 | * @throws InterruptedException If the calling thread is interrupted 36 | */ 37 | void block(long sleepTime) throws InterruptedException; 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/com/github/rholder/retry/BlockStrategies.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012-2015 Ray Holder 3 | * Modifications copyright 2017-2018 Robert Huffman 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package com.github.rholder.retry; 19 | 20 | import javax.annotation.concurrent.Immutable; 21 | 22 | /** 23 | * Factory class for {@link BlockStrategy} instances. 24 | */ 25 | @SuppressWarnings("WeakerAccess") 26 | public final class BlockStrategies { 27 | 28 | private static final BlockStrategy THREAD_SLEEP_STRATEGY = new ThreadSleepStrategy(); 29 | 30 | private BlockStrategies() { 31 | } 32 | 33 | /** 34 | * Returns a block strategy that puts the current thread to sleep between 35 | * retries. 36 | * 37 | * @return a block strategy that puts the current thread to sleep between retries 38 | */ 39 | public static BlockStrategy threadSleepStrategy() { 40 | return THREAD_SLEEP_STRATEGY; 41 | } 42 | 43 | @Immutable 44 | private static class ThreadSleepStrategy implements BlockStrategy { 45 | 46 | @Override 47 | public void block(long sleepTime) throws InterruptedException { 48 | Thread.sleep(sleepTime); 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/test/java/com/github/rholder/retry/AttemptTimeLimitersTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * copyright 2017-2018 Robert Huffman 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 com.github.rholder.retry; 17 | 18 | import com.google.common.collect.Sets; 19 | import org.junit.Test; 20 | 21 | import java.util.Collections; 22 | import java.util.Set; 23 | import java.util.concurrent.Callable; 24 | import java.util.concurrent.TimeUnit; 25 | 26 | import static org.junit.Assert.assertTrue; 27 | import static org.junit.Assert.fail; 28 | 29 | public class AttemptTimeLimitersTest { 30 | 31 | @Test 32 | public void testFixedTimeLimitWithNoExecutorReusesThreads() throws Exception { 33 | Set threadsUsed = Collections.synchronizedSet(Sets.newHashSet()); 34 | Callable callable = () -> { 35 | threadsUsed.add(Thread.currentThread().getId()); 36 | return null; 37 | }; 38 | 39 | int iterations = 20; 40 | for (int i = 0; i < iterations; i++) { 41 | AttemptTimeLimiter timeLimiter = 42 | AttemptTimeLimiters.fixedTimeLimit(1, TimeUnit.SECONDS); 43 | timeLimiter.call(callable); 44 | } 45 | assertTrue("Should have used less than " + iterations + 46 | " threads", threadsUsed.size() < iterations); 47 | } 48 | 49 | } 50 | -------------------------------------------------------------------------------- /src/test/java/com/github/rholder/retry/AttemptTimeLimiterTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012-2015 Ray Holder 3 | * Modifications copyright 2017-2018 Robert Huffman 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package com.github.rholder.retry; 19 | 20 | import org.junit.Assert; 21 | import org.junit.Test; 22 | 23 | import java.util.concurrent.Callable; 24 | import java.util.concurrent.TimeUnit; 25 | 26 | /** 27 | * @author Jason Dunkelberger (dirkraft) 28 | */ 29 | public class AttemptTimeLimiterTest { 30 | 31 | private final Retryer r = RetryerBuilder.newBuilder() 32 | .withAttemptTimeLimiter(AttemptTimeLimiters.fixedTimeLimit(1, TimeUnit.SECONDS)) 33 | .build(); 34 | 35 | @Test 36 | public void testAttemptTimeLimit() throws Exception { 37 | try { 38 | r.call(new SleepyOut(0L)); 39 | } catch (Exception e) { 40 | Assert.fail("Should not timeout"); 41 | } 42 | 43 | try { 44 | r.call(new SleepyOut(10 * 1000L)); 45 | Assert.fail("Expected timeout exception"); 46 | } catch (RetryException ignored) { 47 | } 48 | } 49 | 50 | static class SleepyOut implements Callable { 51 | 52 | final long sleepMs; 53 | 54 | SleepyOut(long sleepMs) { 55 | this.sleepMs = sleepMs; 56 | } 57 | 58 | @Override 59 | public Void call() throws Exception { 60 | Thread.sleep(sleepMs); 61 | return null; 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | set DIRNAME=%~dp0 12 | if "%DIRNAME%" == "" set DIRNAME=. 13 | set APP_BASE_NAME=%~n0 14 | set APP_HOME=%DIRNAME% 15 | 16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 17 | set DEFAULT_JVM_OPTS= 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windows variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | 53 | :win9xME_args 54 | @rem Slurp the command line arguments. 55 | set CMD_LINE_ARGS= 56 | set _SKIP=2 57 | 58 | :win9xME_args_slurp 59 | if "x%~1" == "x" goto execute 60 | 61 | set CMD_LINE_ARGS=%* 62 | 63 | :execute 64 | @rem Setup the command line 65 | 66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 67 | 68 | @rem Execute Gradle 69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 70 | 71 | :end 72 | @rem End local scope for the variables with windows NT shell 73 | if "%ERRORLEVEL%"=="0" goto mainEnd 74 | 75 | :fail 76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 77 | rem the _cmd.exe /c_ return code! 78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 79 | exit /b 1 80 | 81 | :mainEnd 82 | if "%OS%"=="Windows_NT" endlocal 83 | 84 | :omega 85 | -------------------------------------------------------------------------------- /docs/allclasses-noframe.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | All Classes (re-retrying 3.0.1-SNAPSHOT API) 7 | 8 | 9 | 10 | 11 | 12 |

All Classes

13 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /src/test/java/com/github/rholder/retry/StopStrategiesTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012-2015 Ray Holder 3 | * Modifications copyright 2017-2018 Robert Huffman 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package com.github.rholder.retry; 19 | 20 | import org.junit.Test; 21 | 22 | import java.util.concurrent.TimeUnit; 23 | 24 | import static java.util.concurrent.TimeUnit.MILLISECONDS; 25 | import static org.junit.Assert.assertFalse; 26 | import static org.junit.Assert.assertTrue; 27 | 28 | public class StopStrategiesTest { 29 | 30 | @Test 31 | public void testNeverStop() { 32 | assertFalse(StopStrategies.neverStop().shouldStop(failedAttempt(3, 6546L))); 33 | } 34 | 35 | @Test 36 | public void testStopAfterAttempt() { 37 | assertFalse(StopStrategies.stopAfterAttempt(3).shouldStop(failedAttempt(2, 6546L))); 38 | assertTrue(StopStrategies.stopAfterAttempt(3).shouldStop(failedAttempt(3, 6546L))); 39 | assertTrue(StopStrategies.stopAfterAttempt(3).shouldStop(failedAttempt(4, 6546L))); 40 | } 41 | 42 | @Test 43 | public void testStopAfterDelayWithMilliseconds() { 44 | assertFalse(StopStrategies.stopAfterDelay(1000, MILLISECONDS) 45 | .shouldStop(failedAttempt(2, 999L))); 46 | assertTrue(StopStrategies.stopAfterDelay(1000, MILLISECONDS) 47 | .shouldStop(failedAttempt(2, 1000L))); 48 | assertTrue(StopStrategies.stopAfterDelay(1000, MILLISECONDS) 49 | .shouldStop(failedAttempt(2, 1001L))); 50 | } 51 | 52 | @Test 53 | public void testStopAfterDelayWithTimeUnit() { 54 | assertFalse(StopStrategies.stopAfterDelay(1, TimeUnit.SECONDS).shouldStop(failedAttempt(2, 999L))); 55 | assertTrue(StopStrategies.stopAfterDelay(1, TimeUnit.SECONDS).shouldStop(failedAttempt(2, 1000L))); 56 | assertTrue(StopStrategies.stopAfterDelay(1, TimeUnit.SECONDS).shouldStop(failedAttempt(2, 1001L))); 57 | } 58 | 59 | private Attempt failedAttempt(int attemptNumber, long delaySinceFirstAttempt) { 60 | return new Attempt<>(new RuntimeException(), attemptNumber, delaySinceFirstAttempt); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/main/java/com/github/rholder/retry/RetryException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012-2015 Ray Holder 3 | * Modifications copyright 2017-2018 Robert Huffman 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package com.github.rholder.retry; 19 | 20 | import javax.annotation.Nonnull; 21 | import javax.annotation.concurrent.Immutable; 22 | 23 | /** 24 | * An exception indicating that none of the attempts of the {@link Retryer} 25 | * succeeded. If the last {@link Attempt} resulted in an Exception, it is set as 26 | * the cause of the {@link RetryException}. 27 | * 28 | * @author JB 29 | */ 30 | @SuppressWarnings("WeakerAccess") 31 | @Immutable 32 | public final class RetryException extends Exception { 33 | 34 | private final Attempt lastFailedAttempt; 35 | 36 | /** 37 | * If the last {@link Attempt} had an Exception, ensure it is available in 38 | * the stack trace. 39 | * 40 | * @param attempt what happened the last time we failed 41 | */ 42 | RetryException(@Nonnull Attempt attempt) { 43 | this("Retrying failed to complete successfully after " + 44 | attempt.getAttemptNumber() + " attempts.", 45 | attempt); 46 | } 47 | 48 | /** 49 | * If the last {@link Attempt} had an Exception, ensure it is available in 50 | * the stack trace. 51 | * 52 | * @param message Exception description to be added to the stack trace 53 | * @param attempt what happened the last time we failed 54 | */ 55 | private RetryException(String message, Attempt attempt) { 56 | super(message, attempt.hasException() ? attempt.getException() : null); 57 | this.lastFailedAttempt = attempt; 58 | } 59 | 60 | /** 61 | * Returns the number of failed attempts 62 | * 63 | * @return the number of failed attempts 64 | */ 65 | public int getNumberOfFailedAttempts() { 66 | return lastFailedAttempt.getAttemptNumber(); 67 | } 68 | 69 | /** 70 | * Returns the last failed attempt 71 | * 72 | * @return the last failed attempt 73 | */ 74 | public Attempt getLastFailedAttempt() { 75 | return lastFailedAttempt; 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /docs/allclasses-frame.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | All Classes (re-retrying 3.0.1-SNAPSHOT API) 7 | 8 | 9 | 10 | 11 | 12 |

All Classes

13 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /docs/com/github/rholder/retry/package-frame.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | com.github.rholder.retry (re-retrying 3.0.1-SNAPSHOT API) 7 | 8 | 9 | 10 | 11 | 12 |

com.github.rholder.retry

13 |
14 |

Interfaces

15 | 23 |

Classes

24 | 33 |

Exceptions

34 | 37 |
38 | 39 | 40 | -------------------------------------------------------------------------------- /docs/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | re-retrying 3.0.1-SNAPSHOT API 7 | 60 | 61 | 62 | 63 | 64 | 65 | <noscript> 66 | <div>JavaScript is disabled on your browser.</div> 67 | </noscript> 68 | <h2>Frame Alert</h2> 69 | <p>This document is designed to be viewed using the frames feature. If you see this message, you are using a non-frame-capable web client. Link to <a href="com/github/rholder/retry/package-summary.html">Non-frame version</a>.</p> 70 | 71 | 72 | 73 | -------------------------------------------------------------------------------- /docs/constant-values.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Constant Field Values (re-retrying 3.0.1-SNAPSHOT API) 7 | 8 | 9 | 10 | 11 | 12 | 22 | 25 | 26 |
27 | 28 | 29 | 30 | 31 | 32 | 33 | 41 |
42 | 69 | 70 |
71 |

Constant Field Values

72 |

Contents

73 |
74 | 75 |
76 | 77 | 78 | 79 | 80 | 81 | 82 | 90 |
91 | 118 | 119 | 120 | 121 | -------------------------------------------------------------------------------- /src/main/java/com/github/rholder/retry/Attempt.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012-2015 Ray Holder 3 | * Modifications copyright 2017-2018 Robert Huffman 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package com.github.rholder.retry; 19 | 20 | import static com.google.common.base.Preconditions.checkState; 21 | 22 | /** 23 | * An attempt of a call, which resulted either in a result returned by the call, 24 | * or in a Throwable thrown by the call. 25 | * 26 | * @param The type returned by the wrapped callable. 27 | * @author JB 28 | */ 29 | @SuppressWarnings("WeakerAccess") 30 | public class Attempt { 31 | 32 | private final T result; 33 | 34 | private final Throwable throwable; 35 | 36 | private final int attemptNumber; 37 | 38 | private final long delaySinceFirstAttempt; 39 | 40 | Attempt(T result, int attemptNumber, long delaySinceFirstAttempt) { 41 | this.result = result; 42 | this.throwable = null; 43 | this.attemptNumber = attemptNumber; 44 | this.delaySinceFirstAttempt = delaySinceFirstAttempt; 45 | } 46 | 47 | Attempt(Throwable throwable, int attemptNumber, long delaySinceFirstAttempt) { 48 | this.result = null; 49 | this.throwable = throwable; 50 | this.attemptNumber = attemptNumber; 51 | this.delaySinceFirstAttempt = delaySinceFirstAttempt; 52 | } 53 | 54 | /** 55 | * Returns the result of the attempt, if any. 56 | * 57 | * @return the result of the attempt 58 | * @throws IllegalStateException If the attempt resulted in an exception rather 59 | * than returning a result. 60 | */ 61 | public T get() { 62 | checkState(hasResult(), "The attempt resulted in an exception, not in a result"); 63 | return result; 64 | } 65 | 66 | /** 67 | * Tells if the call returned a result or not 68 | * 69 | * @return true if the call returned a result, false 70 | * if it threw an exception 71 | */ 72 | public boolean hasResult() { 73 | // Check the exception field, because the Callable may have succeeded and returned null. 74 | // In that case both exception and result will be null. 75 | return throwable == null; 76 | } 77 | 78 | /** 79 | * Tells if the call threw an exception or not 80 | * 81 | * @return true if the call threw an exception, false 82 | * if it returned a result 83 | */ 84 | public boolean hasException() { 85 | return throwable != null; 86 | } 87 | 88 | /** 89 | * Gets the result of the call 90 | * 91 | * @return the result of the call 92 | * @throws IllegalStateException if the call didn't return a result, but threw an exception, 93 | * as indicated by {@link #hasResult()} 94 | */ 95 | public T getResult() throws IllegalStateException { 96 | return get(); 97 | } 98 | 99 | /** 100 | * Gets the exception thrown by the call 101 | * 102 | * @return the exception thrown by the call 103 | * @throws IllegalStateException if the call didn't throw an exception, 104 | * as indicated by {@link #hasException()} 105 | */ 106 | public Throwable getException() throws IllegalStateException { 107 | checkState(hasException(), "The attempt resulted in a result, not in an exception"); 108 | return throwable; 109 | } 110 | 111 | /** 112 | * The number, starting from 1, of this attempt. 113 | * 114 | * @return the attempt number 115 | */ 116 | public int getAttemptNumber() { 117 | return attemptNumber; 118 | } 119 | 120 | /** 121 | * The delay since the start of the first attempt, in milliseconds. 122 | * 123 | * @return the delay since the start of the first attempt, in milliseconds 124 | */ 125 | public long getDelaySinceFirstAttempt() { 126 | return delaySinceFirstAttempt; 127 | } 128 | } 129 | -------------------------------------------------------------------------------- /src/main/java/com/github/rholder/retry/AttemptTimeLimiters.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012-2015 Ray Holder 3 | * Modifications copyright 2017-2018 Robert Huffman 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package com.github.rholder.retry; 19 | 20 | import com.google.common.base.Preconditions; 21 | import com.google.common.util.concurrent.SimpleTimeLimiter; 22 | import com.google.common.util.concurrent.TimeLimiter; 23 | 24 | import javax.annotation.Nonnull; 25 | import javax.annotation.concurrent.Immutable; 26 | import java.util.concurrent.Callable; 27 | import java.util.concurrent.ExecutorService; 28 | import java.util.concurrent.Executors; 29 | import java.util.concurrent.TimeUnit; 30 | 31 | /** 32 | * Factory class for instances of {@link AttemptTimeLimiter} 33 | * 34 | * @author Jason Dunkelberger (dirkraft) 35 | */ 36 | @SuppressWarnings("WeakerAccess") 37 | public class AttemptTimeLimiters { 38 | 39 | private AttemptTimeLimiters() { 40 | } 41 | 42 | /** 43 | * @return an {@link AttemptTimeLimiter} impl which has no time limit 44 | */ 45 | public static AttemptTimeLimiter noTimeLimit() { 46 | return new NoAttemptTimeLimit(); 47 | } 48 | 49 | /** 50 | * For control over thread management, it is preferable to offer an {@link ExecutorService} 51 | * through the other factory method, {@link #fixedTimeLimit(long, TimeUnit, ExecutorService)}. 52 | * All calls to this method use the same cached thread pool created by 53 | * {@link Executors#newCachedThreadPool()}. It is unbounded, meaning there is no limit to 54 | * the number of threads it will create. It will reuse idle threads if they are available, 55 | * and idle threads remain alive for 60 seconds. 56 | * 57 | * @param duration that an attempt may persist before being circumvented 58 | * @param timeUnit of the 'duration' arg 59 | * @return an {@link AttemptTimeLimiter} with a fixed time limit for each attempt 60 | */ 61 | public static AttemptTimeLimiter fixedTimeLimit(long duration, @Nonnull TimeUnit timeUnit) { 62 | Preconditions.checkNotNull(timeUnit); 63 | return new FixedAttemptTimeLimit(duration, timeUnit); 64 | } 65 | 66 | /** 67 | * @param duration that an attempt may persist before being circumvented 68 | * @param timeUnit of the 'duration' arg 69 | * @param executorService used to enforce time limit 70 | * @return an {@link AttemptTimeLimiter} with a fixed time limit for each attempt 71 | */ 72 | public static AttemptTimeLimiter fixedTimeLimit( 73 | long duration, @Nonnull TimeUnit timeUnit, @Nonnull ExecutorService executorService) { 74 | Preconditions.checkNotNull(timeUnit); 75 | return new FixedAttemptTimeLimit(duration, timeUnit, executorService); 76 | } 77 | 78 | @Immutable 79 | private static final class NoAttemptTimeLimit implements AttemptTimeLimiter { 80 | @Override 81 | public T call(Callable callable) throws Exception { 82 | return callable.call(); 83 | } 84 | } 85 | 86 | @Immutable 87 | private static final class FixedAttemptTimeLimit implements AttemptTimeLimiter { 88 | 89 | /** 90 | * ExecutorService used when no ExecutorService is specified in the constructor 91 | */ 92 | private static final ExecutorService defaultExecutorService = Executors.newCachedThreadPool(); 93 | 94 | private final TimeLimiter timeLimiter; 95 | private final long duration; 96 | private final TimeUnit timeUnit; 97 | 98 | FixedAttemptTimeLimit(long duration, @Nonnull TimeUnit timeUnit) { 99 | this(duration, timeUnit, defaultExecutorService); 100 | } 101 | 102 | FixedAttemptTimeLimit(long duration, @Nonnull TimeUnit timeUnit, @Nonnull ExecutorService executorService) { 103 | this(SimpleTimeLimiter.create(executorService), duration, timeUnit); 104 | } 105 | 106 | private FixedAttemptTimeLimit(@Nonnull TimeLimiter timeLimiter, long duration, @Nonnull TimeUnit timeUnit) { 107 | Preconditions.checkNotNull(timeLimiter); 108 | Preconditions.checkNotNull(timeUnit); 109 | this.timeLimiter = timeLimiter; 110 | this.duration = duration; 111 | this.timeUnit = timeUnit; 112 | } 113 | 114 | @Override 115 | public T call(Callable callable) throws Exception { 116 | return timeLimiter.callWithTimeout(callable, duration, timeUnit); 117 | } 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /docs/deprecated-list.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Deprecated List (re-retrying 3.0.1-SNAPSHOT API) 7 | 8 | 9 | 10 | 11 | 12 | 22 | 25 | 26 |
27 | 28 | 29 | 30 | 31 | 32 | 33 | 41 |
42 | 69 | 70 |
71 |

Deprecated API

72 |

Contents

73 | 76 |
77 |
78 | 79 | 80 | 97 |
98 | 99 |
100 | 101 | 102 | 103 | 104 | 105 | 106 | 114 |
115 | 142 | 143 | 144 | 145 | -------------------------------------------------------------------------------- /docs/serialized-form.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Serialized Form (re-retrying 3.0.1-SNAPSHOT API) 7 | 8 | 9 | 10 | 11 | 12 | 22 | 25 | 26 |
27 | 28 | 29 | 30 | 31 | 32 | 33 | 41 |
42 | 69 | 70 |
71 |

Serialized Form

72 |
73 |
74 |
    75 |
  • 76 |

    Package com.github.rholder.retry

    77 |
      78 |
    • 79 | 80 | 81 |

      Class com.github.rholder.retry.RetryException extends java.lang.Exception implements Serializable

      82 |
        83 |
      • 84 |

        Serialized Fields

        85 |
          86 |
        • 87 |

          numberOfFailedAttempts

          88 |
          int numberOfFailedAttempts
          89 |
        • 90 |
        • 91 |

          lastFailedAttempt

          92 |
          Attempt<V> lastFailedAttempt
          93 |
        • 94 |
        95 |
      • 96 |
      97 |
    • 98 |
    99 |
  • 100 |
101 |
102 | 103 |
104 | 105 | 106 | 107 | 108 | 109 | 110 | 118 |
119 | 146 | 147 | 148 | 149 | -------------------------------------------------------------------------------- /src/main/java/com/github/rholder/retry/StopStrategies.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012-2015 Ray Holder 3 | * Modifications copyright 2017-2018 Robert Huffman 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package com.github.rholder.retry; 19 | 20 | import com.google.common.base.Preconditions; 21 | 22 | import javax.annotation.Nonnull; 23 | import javax.annotation.concurrent.Immutable; 24 | import java.util.concurrent.TimeUnit; 25 | 26 | /** 27 | * Factory class for {@link StopStrategy} instances. 28 | * 29 | * @author JB 30 | */ 31 | public final class StopStrategies { 32 | private static final StopStrategy NEVER_STOP = new NeverStopStrategy(); 33 | 34 | private StopStrategies() { 35 | } 36 | 37 | /** 38 | * Returns a stop strategy which never stops retrying. It might be best to 39 | * try not to abuse services with this kind of behavior when small wait 40 | * intervals between retry attempts are being used. 41 | * 42 | * @return a stop strategy which never stops 43 | */ 44 | @SuppressWarnings("WeakerAccess") 45 | public static StopStrategy neverStop() { 46 | return NEVER_STOP; 47 | } 48 | 49 | /** 50 | * Returns a stop strategy which stops after N failed attempts. 51 | * 52 | * @param attemptNumber the number of failed attempts before stopping 53 | * @return a stop strategy which stops after {@code attemptNumber} attempts 54 | */ 55 | @SuppressWarnings("WeakerAccess") 56 | public static StopStrategy stopAfterAttempt(int attemptNumber) { 57 | return new StopAfterAttemptStrategy(attemptNumber); 58 | } 59 | 60 | /** 61 | * Returns a stop strategy which stops after a given delay. If an 62 | * unsuccessful attempt is made, this {@link StopStrategy} will check if the 63 | * amount of time that's passed from the first attempt has exceeded the 64 | * given delay amount. If it has exceeded this delay, then using this 65 | * strategy causes the retrying to stop. 66 | * 67 | * @param delayInMillis the delay, in milliseconds, starting from first attempt 68 | * @return a stop strategy which stops after {@code delayInMillis} time in milliseconds 69 | * @deprecated Use {@link #stopAfterDelay(long, TimeUnit)} instead. 70 | */ 71 | @Deprecated 72 | public static StopStrategy stopAfterDelay(long delayInMillis) { 73 | return stopAfterDelay(delayInMillis, TimeUnit.MILLISECONDS); 74 | } 75 | 76 | /** 77 | * Returns a stop strategy which stops after a given delay. If an 78 | * unsuccessful attempt is made, this {@link StopStrategy} will check if the 79 | * amount of time that's passed from the first attempt has exceeded the 80 | * given delay amount. If it has exceeded this delay, then using this 81 | * strategy causes the retrying to stop. 82 | * 83 | * @param duration the delay, starting from first attempt 84 | * @param timeUnit the unit of the duration 85 | * @return a stop strategy which stops after {@code delayInMillis} time in milliseconds 86 | */ 87 | @SuppressWarnings("WeakerAccess") 88 | public static StopStrategy stopAfterDelay(long duration, @Nonnull TimeUnit timeUnit) { 89 | Preconditions.checkNotNull(timeUnit, "The time unit may not be null"); 90 | return new StopAfterDelayStrategy(timeUnit.toMillis(duration)); 91 | } 92 | 93 | @Immutable 94 | private static final class NeverStopStrategy implements StopStrategy { 95 | @Override 96 | public boolean shouldStop(Attempt failedAttempt) { 97 | return false; 98 | } 99 | } 100 | 101 | @Immutable 102 | private static final class StopAfterAttemptStrategy implements StopStrategy { 103 | private final int maxAttemptNumber; 104 | 105 | StopAfterAttemptStrategy(int maxAttemptNumber) { 106 | Preconditions.checkArgument(maxAttemptNumber >= 1, "maxAttemptNumber must be >= 1 but is %d", maxAttemptNumber); 107 | this.maxAttemptNumber = maxAttemptNumber; 108 | } 109 | 110 | @Override 111 | public boolean shouldStop(Attempt failedAttempt) { 112 | return failedAttempt.getAttemptNumber() >= maxAttemptNumber; 113 | } 114 | } 115 | 116 | @Immutable 117 | private static final class StopAfterDelayStrategy implements StopStrategy { 118 | private final long maxDelay; 119 | 120 | StopAfterDelayStrategy(long maxDelay) { 121 | Preconditions.checkArgument(maxDelay >= 0L, "maxDelay must be >= 0 but is %d", maxDelay); 122 | this.maxDelay = maxDelay; 123 | } 124 | 125 | @Override 126 | public boolean shouldStop(Attempt failedAttempt) { 127 | return failedAttempt.getDelaySinceFirstAttempt() >= maxDelay; 128 | } 129 | } 130 | } 131 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Attempt to set APP_HOME 10 | # Resolve links: $0 may be a link 11 | PRG="$0" 12 | # Need this for relative symlinks. 13 | while [ -h "$PRG" ] ; do 14 | ls=`ls -ld "$PRG"` 15 | link=`expr "$ls" : '.*-> \(.*\)$'` 16 | if expr "$link" : '/.*' > /dev/null; then 17 | PRG="$link" 18 | else 19 | PRG=`dirname "$PRG"`"/$link" 20 | fi 21 | done 22 | SAVED="`pwd`" 23 | cd "`dirname \"$PRG\"`/" >/dev/null 24 | APP_HOME="`pwd -P`" 25 | cd "$SAVED" >/dev/null 26 | 27 | APP_NAME="Gradle" 28 | APP_BASE_NAME=`basename "$0"` 29 | 30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 31 | DEFAULT_JVM_OPTS="" 32 | 33 | # Use the maximum available, or set MAX_FD != -1 to use that value. 34 | MAX_FD="maximum" 35 | 36 | warn () { 37 | echo "$*" 38 | } 39 | 40 | die () { 41 | echo 42 | echo "$*" 43 | echo 44 | exit 1 45 | } 46 | 47 | # OS specific support (must be 'true' or 'false'). 48 | cygwin=false 49 | msys=false 50 | darwin=false 51 | nonstop=false 52 | case "`uname`" in 53 | CYGWIN* ) 54 | cygwin=true 55 | ;; 56 | Darwin* ) 57 | darwin=true 58 | ;; 59 | MINGW* ) 60 | msys=true 61 | ;; 62 | NONSTOP* ) 63 | nonstop=true 64 | ;; 65 | esac 66 | 67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 68 | 69 | # Determine the Java command to use to start the JVM. 70 | if [ -n "$JAVA_HOME" ] ; then 71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 72 | # IBM's JDK on AIX uses strange locations for the executables 73 | JAVACMD="$JAVA_HOME/jre/sh/java" 74 | else 75 | JAVACMD="$JAVA_HOME/bin/java" 76 | fi 77 | if [ ! -x "$JAVACMD" ] ; then 78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 79 | 80 | Please set the JAVA_HOME variable in your environment to match the 81 | location of your Java installation." 82 | fi 83 | else 84 | JAVACMD="java" 85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 86 | 87 | Please set the JAVA_HOME variable in your environment to match the 88 | location of your Java installation." 89 | fi 90 | 91 | # Increase the maximum file descriptors if we can. 92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 93 | MAX_FD_LIMIT=`ulimit -H -n` 94 | if [ $? -eq 0 ] ; then 95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 96 | MAX_FD="$MAX_FD_LIMIT" 97 | fi 98 | ulimit -n $MAX_FD 99 | if [ $? -ne 0 ] ; then 100 | warn "Could not set maximum file descriptor limit: $MAX_FD" 101 | fi 102 | else 103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 104 | fi 105 | fi 106 | 107 | # For Darwin, add options to specify how the application appears in the dock 108 | if $darwin; then 109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 110 | fi 111 | 112 | # For Cygwin, switch paths to Windows format before running java 113 | if $cygwin ; then 114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 116 | JAVACMD=`cygpath --unix "$JAVACMD"` 117 | 118 | # We build the pattern for arguments to be converted via cygpath 119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 120 | SEP="" 121 | for dir in $ROOTDIRSRAW ; do 122 | ROOTDIRS="$ROOTDIRS$SEP$dir" 123 | SEP="|" 124 | done 125 | OURCYGPATTERN="(^($ROOTDIRS))" 126 | # Add a user-defined pattern to the cygpath arguments 127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 129 | fi 130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 131 | i=0 132 | for arg in "$@" ; do 133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 135 | 136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 138 | else 139 | eval `echo args$i`="\"$arg\"" 140 | fi 141 | i=$((i+1)) 142 | done 143 | case $i in 144 | (0) set -- ;; 145 | (1) set -- "$args0" ;; 146 | (2) set -- "$args0" "$args1" ;; 147 | (3) set -- "$args0" "$args1" "$args2" ;; 148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 154 | esac 155 | fi 156 | 157 | # Escape application args 158 | save () { 159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 160 | echo " " 161 | } 162 | APP_ARGS=$(save "$@") 163 | 164 | # Collect all arguments for the java command, following the shell quoting and substitution rules 165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 166 | 167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong 168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then 169 | cd "$(dirname "$0")" 170 | fi 171 | 172 | exec "$JAVACMD" "$@" 173 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 17 | 18 | [![Build Status](https://travis-ci.org/rhuffman/re-retrying.svg?branch=master)](https://travis-ci.org/rhuffman/re-retrying) 19 | [![Latest Version](http://img.shields.io/badge/latest-3.0.0-brightgreen.svg)](https://github.com/rhuffman/re-retrying/releases/tag/v3.0.0-rc.1) 20 | [![License](http://img.shields.io/badge/license-apache%202-brightgreen.svg)](https://github.com/rhuffman/re-retrying/blob/master/LICENSE) 21 | 22 | ## What is this? 23 | The re-retrying module provides a general purpose method for retrying arbitrary Java code with specific stop, retry, and exception handling capabilities that are enhanced by Guava's predicate matching. 24 | 25 | This is a fork of the [guava-retrying](https://github.com/rholder/guava-retrying) library by Ryan Holder (rholder), which is itself a fork of the [RetryerBuilder](http://code.google.com/p/guava-libraries/issues/detail?id=490) by Jean-Baptiste Nizet (JB). The guava-retrying project added a Gradle build for pushing it up to Maven Central, and exponential and Fibonacci backoff [WaitStrategies](http://rholder.github.io/guava-retrying/javadoc/2.0.0/com/github/rholder/retry/WaitStrategies.html) that might be useful for situations where more well-behaved service polling is preferred. 26 | 27 | Why was this fork necessary? The primary reason was to make it compatible with projects using later versions of Guava. See [this project's Wiki](https://github.com/rhuffman/re-retrying/wiki#why-fork) for more details. 28 | 29 | ## Maven 30 | ```xml 31 | 32 | tech.huffman.re-retrying 33 | re-retrying 34 | 3.0.0 35 | 36 | ``` 37 | 38 | ## Gradle 39 | ```groovy 40 | compile "tech.huffman.re-retrying:re-retrying:3.0.0" 41 | ``` 42 | 43 | ## Quickstart 44 | 45 | Given a function that reads an integer: 46 | ```java 47 | 48 | public int readAnInteger() throws IOException { 49 | ... 50 | } 51 | ``` 52 | 53 | The following will retry if the result of the method is zero, if an `IOException` is thrown, or if any other `RuntimeException` is thrown from the `call()` method. It will stop after attempting to retry 3 times and throw a `RetryException` that contains information about the last failed attempt. If any other `Exception` pops out of the `call()` method it's wrapped and rethrown in an `ExecutionException`. 54 | 55 | ```java 56 | Retryer retryer = RetryerBuilder.newBuilder() 57 | .retryIfResult(Predicates.equalTo(0)) 58 | .retryIfExceptionOfType(IOException.class) 59 | .retryIfRuntimeException() 60 | .withStopStrategy(StopStrategies.stopAfterAttempt(3)) 61 | .build(); 62 | try { 63 | retryer.call(this::readAnInteger); 64 | } catch (RetryException | ExecutionException e) { 65 | e.printStackTrace(); 66 | } 67 | ``` 68 | 69 | ## Exponential Backoff 70 | 71 | Create a `Retryer` that retries forever, waiting after every failed retry in increasing exponential backoff intervals until at most 5 minutes. After 5 minutes, retry from then on in 5 minute intervals. 72 | 73 | ```java 74 | Retryer retryer = RetryerBuilder.newBuilder() 75 | .retryIfExceptionOfType(IOException.class) 76 | .retryIfRuntimeException() 77 | .withWaitStrategy(WaitStrategies.exponentialWait(100, 5, TimeUnit.MINUTES)) 78 | .withStopStrategy(StopStrategies.neverStop()) 79 | .build(); 80 | ``` 81 | You can read more about [exponential backoff](http://en.wikipedia.org/wiki/Exponential_backoff) and the historic role it played in the development of TCP/IP in [Congestion Avoidance and Control](http://ee.lbl.gov/papers/congavoid.pdf). 82 | 83 | ## Fibonacci Backoff 84 | 85 | Create a `Retryer` that retries forever, waiting after every failed retry in increasing Fibonacci backoff intervals until at most 2 minutes. After 2 minutes, retry from then on in 2 minute intervals. 86 | 87 | ```java 88 | Retryer retryer = RetryerBuilder.newBuilder() 89 | .retryIfExceptionOfType(IOException.class) 90 | .retryIfRuntimeException() 91 | .withWaitStrategy(WaitStrategies.fibonacciWait(100, 2, TimeUnit.MINUTES)) 92 | .withStopStrategy(StopStrategies.neverStop()) 93 | .build(); 94 | ``` 95 | 96 | Similar to the `ExponentialWaitStrategy`, the `FibonacciWaitStrategy` follows a pattern of waiting an increasing amount of time after each failed attempt. 97 | 98 | Instead of an exponential function it's (obviously) using a [Fibonacci sequence](https://en.wikipedia.org/wiki/Fibonacci_numbers) to calculate the wait time. 99 | 100 | Depending on the problem at hand, the `FibonacciWaitStrategy` might perform better and lead to better throughput than the `ExponentialWaitStrategy` - at least according to [A Performance Comparison of Different Backoff Algorithms under Different Rebroadcast Probabilities for MANETs](http://www.comp.leeds.ac.uk/ukpew09/papers/12.pdf). 101 | 102 | The implementation of `FibonacciWaitStrategy` is using an iterative version of the Fibonacci because a (naive) recursive version will lead to a [StackOverflowError](http://docs.oracle.com/javase/7/docs/api/java/lang/StackOverflowError.html) at a certain point (although very unlikely with useful parameters for retrying). 103 | 104 | Inspiration for this implementation came from [Efficient retry/backoff mechanisms](https://paperairoplane.net/?p=640). 105 | 106 | ## Documentation 107 | Javadoc can be found [here](http://rholder.github.io/guava-retrying/javadoc/2.0.0). 108 | 109 | ## Building from source 110 | The re-retrying module uses a [Gradle](http://gradle.org)-based build system. In the instructions below, [`./gradlew`](http://vimeo.com/34436402) is invoked from the root of the source tree and serves as a cross-platform, self-contained bootstrap mechanism for the build. The only prerequisites are [Git](https://help.github.com/articles/set-up-git) and JDK 1.8+. 111 | 112 | ### check out sources 113 | `git clone git://github.com/rhuffman/re-retrying.git` 114 | 115 | ### compile and test, build all jars 116 | `./gradlew build` 117 | 118 | ### install all jars into your local Maven cache 119 | `./gradlew install` 120 | 121 | ## License 122 | The re-retrying module is released under version 2.0 of the [Apache License](http://www.apache.org/licenses/LICENSE-2.0). 123 | 124 | ## Contributors 125 | * Jean-Baptiste Nizet (JB) 126 | * Jason Dunkelberger (dirkraft) 127 | * Diwaker Gupta (diwakergupta) 128 | * Jochen Schalanda (joschi) 129 | * Shajahan Palayil (shasts) 130 | * Olivier Grégoire (fror) 131 | * Andrei Savu (andreisavu) 132 | * (tchdp) 133 | * (squalloser) 134 | * Yaroslav Matveychuk (yaroslavm) 135 | * Stephan Schroevers (Stephan202) 136 | * Chad (voiceinsideyou) 137 | * Kevin Conaway (kevinconaway) 138 | * Alberto Scotto (alb-i986) 139 | * Ryan Holder(rholder) 140 | * Robert Huffman (rhuffman) 141 | 142 | -------------------------------------------------------------------------------- /docs/overview-tree.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Class Hierarchy (re-retrying 3.0.1-SNAPSHOT API) 7 | 8 | 9 | 10 | 11 | 12 | 22 | 25 | 26 |
27 | 28 | 29 | 30 | 31 | 32 | 33 | 41 |
42 | 69 | 70 |
71 |

Hierarchy For All Packages

72 | Package Hierarchies: 73 | 76 |
77 |
78 |

Class Hierarchy

79 | 101 |

Interface Hierarchy

102 | 110 |
111 | 112 |
113 | 114 | 115 | 116 | 117 | 118 | 119 | 127 |
128 | 155 | 156 | 157 | 158 | -------------------------------------------------------------------------------- /docs/com/github/rholder/retry/package-tree.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | com.github.rholder.retry Class Hierarchy (re-retrying 3.0.1-SNAPSHOT API) 7 | 8 | 9 | 10 | 11 | 12 | 22 | 25 | 26 |
27 | 28 | 29 | 30 | 31 | 32 | 33 | 41 |
42 | 69 | 70 |
71 |

Hierarchy For Package com.github.rholder.retry

72 |
73 |
74 |

Class Hierarchy

75 | 97 |

Interface Hierarchy

98 | 106 |
107 | 108 |
109 | 110 | 111 | 112 | 113 | 114 | 115 | 123 |
124 | 151 | 152 | 153 | 154 | -------------------------------------------------------------------------------- /docs/help-doc.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | API Help (re-retrying 3.0.1-SNAPSHOT API) 7 | 8 | 9 | 10 | 11 | 12 | 22 | 25 | 26 |
27 | 28 | 29 | 30 | 31 | 32 | 33 | 41 |
42 | 69 | 70 |
71 |

How This API Document Is Organized

72 |
This API (Application Programming Interface) document has pages corresponding to the items in the navigation bar, described as follows.
73 |
74 |
75 |
    76 |
  • 77 |

    Package

    78 |

    Each package has a page that contains a list of its classes and interfaces, with a summary for each. This page can contain six categories:

    79 |
      80 |
    • Interfaces (italic)
    • 81 |
    • Classes
    • 82 |
    • Enums
    • 83 |
    • Exceptions
    • 84 |
    • Errors
    • 85 |
    • Annotation Types
    • 86 |
    87 |
  • 88 |
  • 89 |

    Class/Interface

    90 |

    Each class, interface, nested class and nested interface has its own separate page. Each of these pages has three sections consisting of a class/interface description, summary tables, and detailed member descriptions:

    91 |
      92 |
    • Class inheritance diagram
    • 93 |
    • Direct Subclasses
    • 94 |
    • All Known Subinterfaces
    • 95 |
    • All Known Implementing Classes
    • 96 |
    • Class/interface declaration
    • 97 |
    • Class/interface description
    • 98 |
    99 |
      100 |
    • Nested Class Summary
    • 101 |
    • Field Summary
    • 102 |
    • Constructor Summary
    • 103 |
    • Method Summary
    • 104 |
    105 |
      106 |
    • Field Detail
    • 107 |
    • Constructor Detail
    • 108 |
    • Method Detail
    • 109 |
    110 |

    Each summary entry contains the first sentence from the detailed description for that item. The summary entries are alphabetical, while the detailed descriptions are in the order they appear in the source code. This preserves the logical groupings established by the programmer.

    111 |
  • 112 |
  • 113 |

    Annotation Type

    114 |

    Each annotation type has its own separate page with the following sections:

    115 |
      116 |
    • Annotation Type declaration
    • 117 |
    • Annotation Type description
    • 118 |
    • Required Element Summary
    • 119 |
    • Optional Element Summary
    • 120 |
    • Element Detail
    • 121 |
    122 |
  • 123 |
  • 124 |

    Enum

    125 |

    Each enum has its own separate page with the following sections:

    126 |
      127 |
    • Enum declaration
    • 128 |
    • Enum description
    • 129 |
    • Enum Constant Summary
    • 130 |
    • Enum Constant Detail
    • 131 |
    132 |
  • 133 |
  • 134 |

    Tree (Class Hierarchy)

    135 |

    There is a Class Hierarchy page for all packages, plus a hierarchy for each package. Each hierarchy page contains a list of classes and a list of interfaces. The classes are organized by inheritance structure starting with java.lang.Object. The interfaces do not inherit from java.lang.Object.

    136 |
      137 |
    • When viewing the Overview page, clicking on "Tree" displays the hierarchy for all packages.
    • 138 |
    • When viewing a particular package, class or interface page, clicking "Tree" displays the hierarchy for only that package.
    • 139 |
    140 |
  • 141 |
  • 142 |

    Deprecated API

    143 |

    The Deprecated API page lists all of the API that have been deprecated. A deprecated API is not recommended for use, generally due to improvements, and a replacement API is usually given. Deprecated APIs may be removed in future implementations.

    144 |
  • 145 |
  • 146 |

    Index

    147 |

    The Index contains an alphabetic list of all classes, interfaces, constructors, methods, and fields.

    148 |
  • 149 |
  • 150 |

    Prev/Next

    151 |

    These links take you to the next or previous class, interface, package, or related page.

    152 |
  • 153 |
  • 154 |

    Frames/No Frames

    155 |

    These links show and hide the HTML frames. All pages are available with or without frames.

    156 |
  • 157 |
  • 158 |

    All Classes

    159 |

    The All Classes link shows all classes and interfaces except non-static nested types.

    160 |
  • 161 |
  • 162 |

    Serialized Form

    163 |

    Each serializable or externalizable class has a description of its serialization fields and methods. This information is of interest to re-implementors, not to developers using the API. While there is no link in the navigation bar, you can get to this information by going to any serialized class and clicking "Serialized Form" in the "See also" section of the class description.

    164 |
  • 165 |
  • 166 |

    Constant Field Values

    167 |

    The Constant Field Values page lists the static final fields and their values.

    168 |
  • 169 |
170 | This help file applies to API documentation generated using the standard doclet.
171 | 172 |
173 | 174 | 175 | 176 | 177 | 178 | 179 | 187 |
188 | 215 | 216 | 217 | 218 | -------------------------------------------------------------------------------- /docs/com/github/rholder/retry/WaitStrategy.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | WaitStrategy (re-retrying 3.0.1-SNAPSHOT API) 7 | 8 | 9 | 10 | 11 | 12 | 28 | 31 | 32 |
33 | 34 | 35 | 36 | 37 | 38 | 39 | 47 |
48 | 90 | 91 | 92 |
93 |
com.github.rholder.retry
94 |

Interface WaitStrategy

95 |
96 |
97 |
98 |
    99 |
  • 100 |
    101 |
    102 |
    public interface WaitStrategy
    103 |
    A strategy used to decide how long to sleep before retrying after a failed attempt.
    104 |
  • 105 |
106 |
107 |
108 |
    109 |
  • 110 | 111 | 131 |
  • 132 |
133 |
134 |
135 |
    136 |
  • 137 | 138 |
      139 |
    • 140 | 141 | 142 |

      Method Detail

      143 | 144 | 145 | 146 |
        147 |
      • 148 |

        computeSleepTime

        149 |
        long computeSleepTime(Attempt failedAttempt)
        150 |
        Returns the time, in milliseconds, to sleep before retrying.
        151 |
        152 |
        Parameters:
        153 |
        failedAttempt - the previous failed Attempt
        154 |
        Returns:
        155 |
        the sleep time before next attempt
        156 |
        157 |
      • 158 |
      159 |
    • 160 |
    161 |
  • 162 |
163 |
164 |
165 | 166 | 167 |
168 | 169 | 170 | 171 | 172 | 173 | 174 | 182 |
183 | 225 | 226 | 227 | 228 | -------------------------------------------------------------------------------- /docs/com/github/rholder/retry/StopStrategy.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | StopStrategy (re-retrying 3.0.1-SNAPSHOT API) 7 | 8 | 9 | 10 | 11 | 12 | 28 | 31 | 32 |
33 | 34 | 35 | 36 | 37 | 38 | 39 | 47 |
48 | 90 | 91 | 92 |
93 |
com.github.rholder.retry
94 |

Interface StopStrategy

95 |
96 |
97 |
98 |
    99 |
  • 100 |
    101 |
    102 |
    public interface StopStrategy
    103 |
    A strategy used to decide if a retryer must stop retrying after a failed attempt or not.
    104 |
  • 105 |
106 |
107 |
108 |
    109 |
  • 110 | 111 |
      112 |
    • 113 | 114 | 115 |

      Method Summary

      116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 127 | 128 |
      All Methods Instance Methods Abstract Methods 
      Modifier and TypeMethod and Description
      booleanshouldStop(Attempt failedAttempt) 125 |
      Returns true if the retryer should stop retrying.
      126 |
      129 |
    • 130 |
    131 |
  • 132 |
133 |
134 |
135 |
    136 |
  • 137 | 138 |
      139 |
    • 140 | 141 | 142 |

      Method Detail

      143 | 144 | 145 | 146 |
        147 |
      • 148 |

        shouldStop

        149 |
        boolean shouldStop(Attempt failedAttempt)
        150 |
        Returns true if the retryer should stop retrying.
        151 |
        152 |
        Parameters:
        153 |
        failedAttempt - the previous failed Attempt
        154 |
        Returns:
        155 |
        true if the retryer must stop, false otherwise
        156 |
        157 |
      • 158 |
      159 |
    • 160 |
    161 |
  • 162 |
163 |
164 |
165 | 166 | 167 |
168 | 169 | 170 | 171 | 172 | 173 | 174 | 182 |
183 | 225 | 226 | 227 | 228 | -------------------------------------------------------------------------------- /docs/com/github/rholder/retry/BlockStrategy.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | BlockStrategy (re-retrying 3.0.1-SNAPSHOT API) 7 | 8 | 9 | 10 | 11 | 12 | 28 | 31 | 32 |
33 | 34 | 35 | 36 | 37 | 38 | 39 | 47 |
48 | 90 | 91 | 92 |
93 |
com.github.rholder.retry
94 |

Interface BlockStrategy

95 |
96 |
97 |
98 |
    99 |
  • 100 |
    101 |
    102 |
    public interface BlockStrategy
    103 |
    This is a strategy used to decide how a retryer should block between retry 104 | attempts. Normally this is just a Thread.sleep(), but implementations can be 105 | something more elaborate if desired.
    106 |
  • 107 |
108 |
109 |
110 |
    111 |
  • 112 | 113 |
      114 |
    • 115 | 116 | 117 |

      Method Summary

      118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 129 | 130 |
      All Methods Instance Methods Abstract Methods 
      Modifier and TypeMethod and Description
      voidblock(long sleepTime) 127 |
      Attempt to block for the designated amount of time.
      128 |
      131 |
    • 132 |
    133 |
  • 134 |
135 |
136 |
137 |
    138 |
  • 139 | 140 |
      141 |
    • 142 | 143 | 144 |

      Method Detail

      145 | 146 | 147 | 148 |
        149 |
      • 150 |

        block

        151 |
        void block(long sleepTime)
        152 |     throws java.lang.InterruptedException
        153 |
        Attempt to block for the designated amount of time. Implementations 154 | that don't block or otherwise delay the processing from within this 155 | method for the given sleep duration can significantly modify the behavior 156 | of any configured WaitStrategy. Caution 157 | is advised when generating your own implementations.
        158 |
        159 |
        Parameters:
        160 |
        sleepTime - the computed sleep duration in milliseconds
        161 |
        Throws:
        162 |
        java.lang.InterruptedException - If the calling thread is interrupted
        163 |
        164 |
      • 165 |
      166 |
    • 167 |
    168 |
  • 169 |
170 |
171 |
172 | 173 | 174 |
175 | 176 | 177 | 178 | 179 | 180 | 181 | 189 |
190 | 232 | 233 | 234 | 235 | -------------------------------------------------------------------------------- /docs/com/github/rholder/retry/RetryListener.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | RetryListener (re-retrying 3.0.1-SNAPSHOT API) 7 | 8 | 9 | 10 | 11 | 12 | 28 | 31 | 32 |
33 | 34 | 35 | 36 | 37 | 38 | 39 | 47 |
48 | 90 | 91 | 92 |
93 |
com.github.rholder.retry
94 |

Interface RetryListener

95 |
96 |
97 |
98 |
    99 |
  • 100 |
    101 |
    102 |
    @Beta
    103 | public interface RetryListener
    104 |
    This listener provides callbacks for several events that occur when running 105 | code through a Retryer instance.
    106 |
  • 107 |
108 |
109 |
110 |
    111 |
  • 112 | 113 |
      114 |
    • 115 | 116 | 117 |

      Method Summary

      118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 130 | 131 |
      All Methods Instance Methods Abstract Methods 
      Modifier and TypeMethod and Description
      <V> voidonRetry(Attempt<V> attempt) 127 |
      This method with fire no matter what the result is and before the 128 | rejection predicate and stop strategies are applied.
      129 |
      132 |
    • 133 |
    134 |
  • 135 |
136 |
137 |
138 |
    139 |
  • 140 | 141 |
      142 |
    • 143 | 144 | 145 |

      Method Detail

      146 | 147 | 148 | 149 |
        150 |
      • 151 |

        onRetry

        152 |
        <V> void onRetry(Attempt<V> attempt)
        153 |
        This method with fire no matter what the result is and before the 154 | rejection predicate and stop strategies are applied.
        155 |
        156 |
        Type Parameters:
        157 |
        V - the type returned by the retryer callable
        158 |
        Parameters:
        159 |
        attempt - the current Attempt
        160 |
        161 |
      • 162 |
      163 |
    • 164 |
    165 |
  • 166 |
167 |
168 |
169 | 170 | 171 |
172 | 173 | 174 | 175 | 176 | 177 | 178 | 186 |
187 | 229 | 230 | 231 | 232 | -------------------------------------------------------------------------------- /docs/com/github/rholder/retry/AttemptTimeLimiter.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | AttemptTimeLimiter (re-retrying 3.0.1-SNAPSHOT API) 7 | 8 | 9 | 10 | 11 | 12 | 28 | 31 | 32 |
33 | 34 | 35 | 36 | 37 | 38 | 39 | 47 |
48 | 90 | 91 | 92 |
93 |
com.github.rholder.retry
94 |

Interface AttemptTimeLimiter<V>

95 |
96 |
97 |
98 |
    99 |
  • 100 |
    101 |
    Type Parameters:
    102 |
    V - return type of Callable
    103 |
    104 |
    105 |
    106 |
    public interface AttemptTimeLimiter<V>
    107 |
    A rule to wrap any single attempt in a time limit, where it will possibly be interrupted if the limit is exceeded.
    108 |
  • 109 |
110 |
111 |
112 |
    113 |
  • 114 | 115 |
      116 |
    • 117 | 118 | 119 |

      Method Summary

      120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 |
      All Methods Instance Methods Abstract Methods 
      Modifier and TypeMethod and Description
      Vcall(java.util.concurrent.Callable<V> callable) 
      131 |
    • 132 |
    133 |
  • 134 |
135 |
136 |
137 |
    138 |
  • 139 | 140 |
      141 |
    • 142 | 143 | 144 |

      Method Detail

      145 | 146 | 147 | 148 |
        149 |
      • 150 |

        call

        151 |
        V call(java.util.concurrent.Callable<V> callable)
        152 | throws java.lang.Exception
        153 |
        154 |
        Parameters:
        155 |
        callable - to subject to the time limit
        156 |
        Returns:
        157 |
        the return of the given callable
        158 |
        Throws:
        159 |
        java.lang.Exception - any exception from this invocation
        160 |
        161 |
      • 162 |
      163 |
    • 164 |
    165 |
  • 166 |
167 |
168 |
169 | 170 | 171 |
172 | 173 | 174 | 175 | 176 | 177 | 178 | 186 |
187 | 229 | 230 | 231 | 232 | -------------------------------------------------------------------------------- /docs/com/github/rholder/retry/BlockStrategies.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | BlockStrategies (re-retrying 3.0.1-SNAPSHOT API) 7 | 8 | 9 | 10 | 11 | 12 | 28 | 31 | 32 |
33 | 34 | 35 | 36 | 37 | 38 | 39 | 47 |
48 | 90 | 91 | 92 |
93 |
com.github.rholder.retry
94 |

Class BlockStrategies

95 |
96 |
97 |
    98 |
  • java.lang.Object
  • 99 |
  • 100 |
      101 |
    • com.github.rholder.retry.BlockStrategies
    • 102 |
    103 |
  • 104 |
105 |
106 |
    107 |
  • 108 |
    109 |
    110 |
    public final class BlockStrategies
    111 | extends java.lang.Object
    112 |
    Factory class for BlockStrategy instances.
    113 |
  • 114 |
115 |
116 |
117 |
    118 |
  • 119 | 120 |
      121 |
    • 122 | 123 | 124 |

      Method Summary

      125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 137 | 138 |
      All Methods Static Methods Concrete Methods 
      Modifier and TypeMethod and Description
      static BlockStrategythreadSleepStrategy() 134 |
      Returns a block strategy that puts the current thread to sleep between 135 | retries.
      136 |
      139 |
        140 |
      • 141 | 142 | 143 |

        Methods inherited from class java.lang.Object

        144 | clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
      • 145 |
      146 |
    • 147 |
    148 |
  • 149 |
150 |
151 |
152 |
    153 |
  • 154 | 155 |
      156 |
    • 157 | 158 | 159 |

      Method Detail

      160 | 161 | 162 | 163 |
        164 |
      • 165 |

        threadSleepStrategy

        166 |
        public static BlockStrategy threadSleepStrategy()
        167 |
        Returns a block strategy that puts the current thread to sleep between 168 | retries.
        169 |
        170 |
        Returns:
        171 |
        a block strategy that puts the current thread to sleep between retries
        172 |
        173 |
      • 174 |
      175 |
    • 176 |
    177 |
  • 178 |
179 |
180 |
181 | 182 | 183 |
184 | 185 | 186 | 187 | 188 | 189 | 190 | 198 |
199 | 241 | 242 | 243 | 244 | -------------------------------------------------------------------------------- /src/main/java/com/github/rholder/retry/Retryer.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012-2015 Ray Holder 3 | * Modifications copyright 2017-2018 Robert Huffman 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package com.github.rholder.retry; 19 | 20 | import com.google.common.base.Preconditions; 21 | 22 | import javax.annotation.Nonnull; 23 | import java.util.Collection; 24 | import java.util.List; 25 | import java.util.concurrent.Callable; 26 | import java.util.function.Predicate; 27 | 28 | /** 29 | * A retryer, which executes a call, and retries it until it succeeds, or 30 | * a stop strategy decides to stop retrying. A wait strategy is used to sleep 31 | * between attempts. The strategy to decide if the call succeeds or not is 32 | * also configurable. 33 | *

34 | * A retryer can also wrap the callable into a RetryerCallable, which can be submitted to an executor. 35 | *

36 | * Retryer instances are better constructed with a {@link RetryerBuilder}. A retryer 37 | * is thread-safe, provided the arguments passed to its constructor are thread-safe. 38 | * 39 | * @author JB 40 | * @author Jason Dunkelberger (dirkraft) 41 | */ 42 | public final class Retryer { 43 | private final StopStrategy stopStrategy; 44 | private final WaitStrategy waitStrategy; 45 | private final BlockStrategy blockStrategy; 46 | private final AttemptTimeLimiter attemptTimeLimiter; 47 | private final List>> retryPredicates; 48 | private final Collection listeners; 49 | 50 | /** 51 | * @param attemptTimeLimiter to prevent from any single attempt from spinning infinitely 52 | * @param stopStrategy the strategy used to decide when the retryer must stop retrying 53 | * @param waitStrategy the strategy used to decide how much time to sleep between attempts 54 | * @param blockStrategy the strategy used to decide how to block between retry attempts; 55 | * eg, Thread#sleep(), latches, etc. 56 | * @param retryPredicates the predicates used to decide if the attempt must be retried (without 57 | * regard to the StopStrategy). 58 | * @param listeners collection of retry listeners 59 | */ 60 | Retryer(@Nonnull AttemptTimeLimiter attemptTimeLimiter, 61 | @Nonnull StopStrategy stopStrategy, 62 | @Nonnull WaitStrategy waitStrategy, 63 | @Nonnull BlockStrategy blockStrategy, 64 | @Nonnull List>> retryPredicates, 65 | @Nonnull Collection listeners) { 66 | Preconditions.checkNotNull(attemptTimeLimiter, "timeLimiter may not be null"); 67 | Preconditions.checkNotNull(stopStrategy, "stopStrategy may not be null"); 68 | Preconditions.checkNotNull(waitStrategy, "waitStrategy may not be null"); 69 | Preconditions.checkNotNull(blockStrategy, "blockStrategy may not be null"); 70 | Preconditions.checkNotNull(retryPredicates, "retryPredicates may not be null"); 71 | Preconditions.checkNotNull(listeners, "listeners may not null"); 72 | 73 | this.attemptTimeLimiter = attemptTimeLimiter; 74 | this.stopStrategy = stopStrategy; 75 | this.waitStrategy = waitStrategy; 76 | this.blockStrategy = blockStrategy; 77 | this.retryPredicates = retryPredicates; 78 | this.listeners = listeners; 79 | } 80 | 81 | /** 82 | * Executes the given callable, retrying if necessary. If the retry predicate 83 | * accepts the attempt, the stop strategy is used to decide if a new attempt 84 | * must be made. Then the wait strategy is used to decide how much time to sleep 85 | * and a new attempt is made. 86 | * 87 | * @param callable the callable task to be executed 88 | * @param the return type of the Callable 89 | * @return the computed result of the given callable 90 | * @throws RetryException if all the attempts failed before the stop strategy decided to abort 91 | * @throws InterruptedException If this thread is interrupted. This can happen because 92 | * {@link Thread#sleep} is invoked between attempts 93 | */ 94 | public T call(Callable callable) throws RetryException, InterruptedException { 95 | long startTimeMillis = System.currentTimeMillis(); 96 | for (int attemptNumber = 1; ; attemptNumber++) { 97 | Attempt attempt; 98 | try { 99 | T result = attemptTimeLimiter.call(callable); 100 | attempt = new Attempt<>(result, attemptNumber, System.currentTimeMillis() - startTimeMillis); 101 | } catch(InterruptedException e) { 102 | throw e; 103 | } catch (Throwable t) { 104 | attempt = new Attempt<>(t, attemptNumber, System.currentTimeMillis() - startTimeMillis); 105 | } 106 | 107 | for (RetryListener listener : listeners) { 108 | listener.onRetry(attempt); 109 | } 110 | 111 | if (!shouldRetry(attempt)) { 112 | return getOrThrow(attempt); 113 | } 114 | 115 | if (stopStrategy.shouldStop(attempt)) { 116 | throw new RetryException(attempt); 117 | } else { 118 | long sleepTime = waitStrategy.computeSleepTime(attempt); 119 | blockStrategy.block(sleepTime); 120 | } 121 | } 122 | } 123 | 124 | /** 125 | * Executes the given runnable, retrying if necessary. If the retry predicate 126 | * accepts the attempt, the stop strategy is used to decide if a new attempt 127 | * must be made. Then the wait strategy is used to decide how much time to sleep 128 | * and a new attempt is made. 129 | * 130 | * @param runnable the runnable task to be executed 131 | * @throws RetryException if all the attempts failed before the stop strategy decided 132 | * to abort 133 | * @throws InterruptedException If this thread is interrupted. This can happen because 134 | * {@link Thread#sleep} is invoked between attempts 135 | */ 136 | @SuppressWarnings("WeakerAccess") 137 | public void run(Runnable runnable) throws RetryException, InterruptedException { 138 | call(() -> { 139 | runnable.run(); 140 | return null; 141 | }); 142 | } 143 | 144 | /** 145 | * Throw the Attempt's exception, if it has one, wrapped in a RetryException. Otherwise, 146 | * return the attempt's result. 147 | * 148 | * @param attempt An attempt that was made by invoking the call 149 | * @param The type of the attempt 150 | * @return The result of the attempt 151 | * @throws RetryException If the attempt has an exception 152 | */ 153 | private T getOrThrow(Attempt attempt) throws RetryException { 154 | if (attempt.hasException()) { 155 | throw new RetryException(attempt); 156 | } 157 | return attempt.get(); 158 | } 159 | 160 | /** 161 | * Applies the retry predicates to the attempt, in order, until either one 162 | * predicate returns true or all predicates return false. 163 | * 164 | * @param attempt The attempt made by invoking the call 165 | */ 166 | private boolean shouldRetry(Attempt attempt) { 167 | for (Predicate> predicate : retryPredicates) { 168 | if (predicate.test(attempt)) { 169 | return true; 170 | } 171 | } 172 | return false; 173 | } 174 | 175 | /** 176 | * Wraps the given {@link Callable} in a {@link RetryerCallable}, which can 177 | * be submitted to an executor. The returned {@link RetryerCallable} uses 178 | * this {@link Retryer} instance to call the given {@link Callable}. 179 | * 180 | * @param callable the callable to wrap 181 | * @param the return type of the Callable 182 | * @return a {@link RetryerCallable} that behaves like the given {@link Callable} with retry behavior defined by this {@link Retryer} 183 | */ 184 | @SuppressWarnings("WeakerAccess") 185 | public RetryerCallable wrap(Callable callable) { 186 | return new RetryerCallable<>(this, callable); 187 | } 188 | 189 | /** 190 | * A {@link Callable} which wraps another {@link Callable} in order to add 191 | * retrying behavior from a given {@link Retryer} instance. 192 | * 193 | * @author JB 194 | */ 195 | public static class RetryerCallable implements Callable { 196 | private Retryer retryer; 197 | private Callable callable; 198 | 199 | private RetryerCallable(Retryer retryer, 200 | Callable callable) { 201 | this.retryer = retryer; 202 | this.callable = callable; 203 | } 204 | 205 | /** 206 | * Makes the enclosing retryer call the wrapped callable. 207 | * 208 | * @see Retryer#call(Callable) 209 | */ 210 | @Override 211 | public T call() throws Exception { 212 | return retryer.call(callable); 213 | } 214 | } 215 | } 216 | -------------------------------------------------------------------------------- /src/test/java/com/github/rholder/retry/WaitStrategiesTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012-2015 Ray Holder 3 | * Modifications copyright 2017-2018 Robert Huffman 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package com.github.rholder.retry; 19 | 20 | import com.google.common.collect.Sets; 21 | import org.junit.Test; 22 | 23 | import java.util.Set; 24 | import java.util.concurrent.TimeUnit; 25 | import java.util.function.Function; 26 | 27 | import static org.junit.Assert.assertEquals; 28 | import static org.junit.Assert.assertTrue; 29 | 30 | public class WaitStrategiesTest { 31 | 32 | 33 | @Test 34 | public void testNoWait() { 35 | WaitStrategy noWait = WaitStrategies.noWait(); 36 | assertEquals(0L, noWait.computeSleepTime(failedAttempt(18, 9879L))); 37 | } 38 | 39 | @Test 40 | public void testFixedWait() { 41 | WaitStrategy fixedWait = WaitStrategies.fixedWait(1000L, TimeUnit.MILLISECONDS); 42 | assertEquals(1000L, fixedWait.computeSleepTime(failedAttempt(12, 6546L))); 43 | } 44 | 45 | @Test 46 | public void testIncrementingWait() { 47 | WaitStrategy incrementingWait = WaitStrategies.incrementingWait(500L, TimeUnit.MILLISECONDS, 100L, TimeUnit.MILLISECONDS); 48 | assertEquals(500L, incrementingWait.computeSleepTime(failedAttempt(1, 6546L))); 49 | assertEquals(600L, incrementingWait.computeSleepTime(failedAttempt(2, 6546L))); 50 | assertEquals(700L, incrementingWait.computeSleepTime(failedAttempt(3, 6546L))); 51 | } 52 | 53 | @Test 54 | public void testRandomWait() { 55 | WaitStrategy randomWait = WaitStrategies.randomWait(1000L, TimeUnit.MILLISECONDS, 2000L, TimeUnit.MILLISECONDS); 56 | Set times = Sets.newHashSet(); 57 | times.add(randomWait.computeSleepTime(failedAttempt(1, 6546L))); 58 | times.add(randomWait.computeSleepTime(failedAttempt(1, 6546L))); 59 | times.add(randomWait.computeSleepTime(failedAttempt(1, 6546L))); 60 | times.add(randomWait.computeSleepTime(failedAttempt(1, 6546L))); 61 | assertTrue(times.size() > 1); // if not, the random is not random 62 | for (long time : times) { 63 | assertTrue(time >= 1000L); 64 | assertTrue(time <= 2000L); 65 | } 66 | } 67 | 68 | @Test 69 | public void testRandomWaitWithoutMinimum() { 70 | WaitStrategy randomWait = WaitStrategies.randomWait(2000L, TimeUnit.MILLISECONDS); 71 | Set times = Sets.newHashSet(); 72 | times.add(randomWait.computeSleepTime(failedAttempt(1, 6546L))); 73 | times.add(randomWait.computeSleepTime(failedAttempt(1, 6546L))); 74 | times.add(randomWait.computeSleepTime(failedAttempt(1, 6546L))); 75 | times.add(randomWait.computeSleepTime(failedAttempt(1, 6546L))); 76 | assertTrue(times.size() > 1); // if not, the random is not random 77 | for (long time : times) { 78 | assertTrue(time >= 0L); 79 | assertTrue(time <= 2000L); 80 | } 81 | } 82 | 83 | @Test 84 | public void testExponential() { 85 | WaitStrategy exponentialWait = WaitStrategies.exponentialWait(); 86 | assertTrue(exponentialWait.computeSleepTime(failedAttempt(1, 0)) == 2); 87 | assertTrue(exponentialWait.computeSleepTime(failedAttempt(2, 0)) == 4); 88 | assertTrue(exponentialWait.computeSleepTime(failedAttempt(3, 0)) == 8); 89 | assertTrue(exponentialWait.computeSleepTime(failedAttempt(4, 0)) == 16); 90 | assertTrue(exponentialWait.computeSleepTime(failedAttempt(5, 0)) == 32); 91 | assertTrue(exponentialWait.computeSleepTime(failedAttempt(6, 0)) == 64); 92 | } 93 | 94 | @Test 95 | public void testExponentialWithMaximumWait() { 96 | WaitStrategy exponentialWait = WaitStrategies.exponentialWait(40, TimeUnit.MILLISECONDS); 97 | assertTrue(exponentialWait.computeSleepTime(failedAttempt(1, 0)) == 2); 98 | assertTrue(exponentialWait.computeSleepTime(failedAttempt(2, 0)) == 4); 99 | assertTrue(exponentialWait.computeSleepTime(failedAttempt(3, 0)) == 8); 100 | assertTrue(exponentialWait.computeSleepTime(failedAttempt(4, 0)) == 16); 101 | assertTrue(exponentialWait.computeSleepTime(failedAttempt(5, 0)) == 32); 102 | assertTrue(exponentialWait.computeSleepTime(failedAttempt(6, 0)) == 40); 103 | assertTrue(exponentialWait.computeSleepTime(failedAttempt(7, 0)) == 40); 104 | assertTrue(exponentialWait.computeSleepTime(failedAttempt(8, 0)) == 40); 105 | } 106 | 107 | @Test 108 | public void testExponentialWithMultiplierAndMaximumWait() { 109 | WaitStrategy exponentialWait = WaitStrategies.exponentialWait(1000, 50000, TimeUnit.MILLISECONDS); 110 | assertTrue(exponentialWait.computeSleepTime(failedAttempt(1, 0)) == 2000); 111 | assertTrue(exponentialWait.computeSleepTime(failedAttempt(2, 0)) == 4000); 112 | assertTrue(exponentialWait.computeSleepTime(failedAttempt(3, 0)) == 8000); 113 | assertTrue(exponentialWait.computeSleepTime(failedAttempt(4, 0)) == 16000); 114 | assertTrue(exponentialWait.computeSleepTime(failedAttempt(5, 0)) == 32000); 115 | assertTrue(exponentialWait.computeSleepTime(failedAttempt(6, 0)) == 50000); 116 | assertTrue(exponentialWait.computeSleepTime(failedAttempt(7, 0)) == 50000); 117 | assertTrue(exponentialWait.computeSleepTime(failedAttempt(8, 0)) == 50000); 118 | } 119 | 120 | @Test 121 | public void testFibonacci() { 122 | WaitStrategy fibonacciWait = WaitStrategies.fibonacciWait(); 123 | assertTrue(fibonacciWait.computeSleepTime(failedAttempt(1, 0L)) == 1L); 124 | assertTrue(fibonacciWait.computeSleepTime(failedAttempt(2, 0L)) == 1L); 125 | assertTrue(fibonacciWait.computeSleepTime(failedAttempt(3, 0L)) == 2L); 126 | assertTrue(fibonacciWait.computeSleepTime(failedAttempt(4, 0L)) == 3L); 127 | assertTrue(fibonacciWait.computeSleepTime(failedAttempt(5, 0L)) == 5L); 128 | assertTrue(fibonacciWait.computeSleepTime(failedAttempt(6, 0L)) == 8L); 129 | } 130 | 131 | @Test 132 | public void testFibonacciWithMaximumWait() { 133 | WaitStrategy fibonacciWait = WaitStrategies.fibonacciWait(10L, TimeUnit.MILLISECONDS); 134 | assertTrue(fibonacciWait.computeSleepTime(failedAttempt(1, 0L)) == 1L); 135 | assertTrue(fibonacciWait.computeSleepTime(failedAttempt(2, 0L)) == 1L); 136 | assertTrue(fibonacciWait.computeSleepTime(failedAttempt(3, 0L)) == 2L); 137 | assertTrue(fibonacciWait.computeSleepTime(failedAttempt(4, 0L)) == 3L); 138 | assertTrue(fibonacciWait.computeSleepTime(failedAttempt(5, 0L)) == 5L); 139 | assertTrue(fibonacciWait.computeSleepTime(failedAttempt(6, 0L)) == 8L); 140 | assertTrue(fibonacciWait.computeSleepTime(failedAttempt(7, 0L)) == 10L); 141 | assertTrue(fibonacciWait.computeSleepTime(failedAttempt(8, 0L)) == 10L); 142 | } 143 | 144 | @Test 145 | public void testFibonacciWithMultiplierAndMaximumWait() { 146 | WaitStrategy fibonacciWait = WaitStrategies.fibonacciWait(1000L, 50000L, TimeUnit.MILLISECONDS); 147 | assertTrue(fibonacciWait.computeSleepTime(failedAttempt(1, 0L)) == 1000L); 148 | assertTrue(fibonacciWait.computeSleepTime(failedAttempt(2, 0L)) == 1000L); 149 | assertTrue(fibonacciWait.computeSleepTime(failedAttempt(3, 0L)) == 2000L); 150 | assertTrue(fibonacciWait.computeSleepTime(failedAttempt(4, 0L)) == 3000L); 151 | assertTrue(fibonacciWait.computeSleepTime(failedAttempt(5, 0L)) == 5000L); 152 | assertTrue(fibonacciWait.computeSleepTime(failedAttempt(6, 0L)) == 8000L); 153 | assertTrue(fibonacciWait.computeSleepTime(failedAttempt(7, 0L)) == 13000L); 154 | assertTrue(fibonacciWait.computeSleepTime(failedAttempt(10, 0L)) == 50000L); 155 | } 156 | 157 | @Test 158 | public void testExceptionWait() { 159 | WaitStrategy exceptionWait = WaitStrategies.exceptionWait( 160 | RuntimeException.class, zeroSleepFunction()); 161 | assertEquals(0L, exceptionWait.computeSleepTime(failedAttempt(42, 7227))); 162 | 163 | WaitStrategy oneMinuteWait = WaitStrategies.exceptionWait(RuntimeException.class, oneMinuteSleepFunction()); 164 | assertEquals(3600 * 1000L, oneMinuteWait.computeSleepTime(failedAttempt(42, 7227))); 165 | 166 | WaitStrategy noMatchRetryAfterWait = WaitStrategies.exceptionWait(RetryAfterException.class, customSleepFunction()); 167 | assertEquals(0L, noMatchRetryAfterWait.computeSleepTime(failedAttempt(42, 7227))); 168 | 169 | WaitStrategy retryAfterWait = WaitStrategies.exceptionWait(RetryAfterException.class, customSleepFunction()); 170 | Attempt failedAttempt = new Attempt<>( 171 | new RetryAfterException(), 42, 7227L); 172 | assertEquals(29L, retryAfterWait.computeSleepTime(failedAttempt)); 173 | } 174 | 175 | private Attempt failedAttempt(int attemptNumber, long delaySinceFirstAttempt) { 176 | return new Attempt<>(new RuntimeException(), attemptNumber, delaySinceFirstAttempt); 177 | } 178 | 179 | private Function zeroSleepFunction() { 180 | return input -> 0L; 181 | } 182 | 183 | private Function oneMinuteSleepFunction() { 184 | return input -> 3600 * 1000L; 185 | } 186 | 187 | private Function customSleepFunction() { 188 | return RetryAfterException::getRetryAfter; 189 | } 190 | 191 | public class RetryAfterException extends RuntimeException { 192 | private final long retryAfter = 29L; 193 | 194 | long getRetryAfter() { 195 | return retryAfter; 196 | } 197 | } 198 | } 199 | -------------------------------------------------------------------------------- /src/main/java/com/github/rholder/retry/RetryerBuilder.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012-2015 Ray Holder 3 | * Modifications copyright 2017-2018 Robert Huffman 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package com.github.rholder.retry; 19 | 20 | import com.google.common.base.Preconditions; 21 | import com.google.common.collect.Lists; 22 | 23 | import javax.annotation.Nonnull; 24 | import java.util.ArrayList; 25 | import java.util.List; 26 | import java.util.function.Predicate; 27 | 28 | /** 29 | * A builder used to configure and create a {@link Retryer}. 30 | * 31 | * @author JB 32 | * @author Jason Dunkelberger (dirkraft) 33 | */ 34 | @SuppressWarnings("WeakerAccess") 35 | public class RetryerBuilder { 36 | private AttemptTimeLimiter attemptTimeLimiter; 37 | private StopStrategy stopStrategy; 38 | private WaitStrategy waitStrategy; 39 | private BlockStrategy blockStrategy; 40 | private List>> retryPredicates = Lists.newArrayList(); 41 | private List listeners = new ArrayList<>(); 42 | 43 | private RetryerBuilder() { 44 | } 45 | 46 | public static RetryerBuilder newBuilder() { 47 | return new RetryerBuilder(); 48 | } 49 | 50 | /** 51 | * Adds a listener that will be notified of each attempt that is made 52 | * 53 | * @param listener Listener to add 54 | * @return this 55 | */ 56 | public RetryerBuilder withRetryListener(@Nonnull RetryListener listener) { 57 | Preconditions.checkNotNull(listener, "listener may not be null"); 58 | listeners.add(listener); 59 | return this; 60 | } 61 | 62 | /** 63 | * Sets the wait strategy used to decide how long to sleep between failed attempts. 64 | * The default strategy is to retry immediately after a failed attempt. 65 | * 66 | * @param waitStrategy the strategy used to sleep between failed attempts 67 | * @return this 68 | * @throws IllegalStateException if a wait strategy has already been set. 69 | */ 70 | public RetryerBuilder withWaitStrategy(@Nonnull WaitStrategy waitStrategy) 71 | throws IllegalStateException { 72 | Preconditions.checkNotNull(waitStrategy, "waitStrategy may not be null"); 73 | Preconditions.checkState(this.waitStrategy == null, 74 | "a wait strategy has already been set %s", this.waitStrategy); 75 | this.waitStrategy = waitStrategy; 76 | return this; 77 | } 78 | 79 | /** 80 | * Sets the stop strategy used to decide when to stop retrying. The default strategy 81 | * is to not stop at all . 82 | * 83 | * @param stopStrategy the strategy used to decide when to stop retrying 84 | * @return this 85 | * @throws IllegalStateException if a stop strategy has already been set. 86 | */ 87 | public RetryerBuilder withStopStrategy(@Nonnull StopStrategy stopStrategy) 88 | throws IllegalStateException { 89 | Preconditions.checkNotNull(stopStrategy, "stopStrategy may not be null"); 90 | Preconditions.checkState(this.stopStrategy == null, "a stop strategy has already been set %s", this.stopStrategy); 91 | this.stopStrategy = stopStrategy; 92 | return this; 93 | } 94 | 95 | /** 96 | * Sets the block strategy used to decide how to block between retry attempts. The default strategy is to use Thread#sleep(). 97 | * 98 | * @param blockStrategy the strategy used to decide how to block between retry attempts 99 | * @return this 100 | * @throws IllegalStateException if a block strategy has already been set. 101 | */ 102 | public RetryerBuilder withBlockStrategy(@Nonnull BlockStrategy blockStrategy) 103 | throws IllegalStateException { 104 | Preconditions.checkNotNull(blockStrategy, "blockStrategy may not be null"); 105 | Preconditions.checkState(this.blockStrategy == null, 106 | "a block strategy has already been set %s", this.blockStrategy); 107 | this.blockStrategy = blockStrategy; 108 | return this; 109 | } 110 | 111 | 112 | /** 113 | * Configures the retryer to limit the duration of any particular attempt by the given duration. 114 | * 115 | * @param attemptTimeLimiter to apply to each attempt 116 | * @return this 117 | */ 118 | public RetryerBuilder withAttemptTimeLimiter(@Nonnull AttemptTimeLimiter attemptTimeLimiter) { 119 | Preconditions.checkNotNull(attemptTimeLimiter); 120 | this.attemptTimeLimiter = attemptTimeLimiter; 121 | return this; 122 | } 123 | 124 | /** 125 | * Configures the retryer to retry if an exception (i.e. any Exception or subclass 126 | * of Exception) is thrown by the call. 127 | * 128 | * @return this 129 | */ 130 | public RetryerBuilder retryIfException() { 131 | retryPredicates.add(new ExceptionClassPredicate(Exception.class)); 132 | return this; 133 | } 134 | 135 | /** 136 | * Configures the retryer to retry if a runtime exception (i.e. any RuntimeException or subclass 137 | * of RuntimeException) is thrown by the call. 138 | * 139 | * @return this 140 | */ 141 | public RetryerBuilder retryIfRuntimeException() { 142 | retryPredicates.add(new ExceptionClassPredicate(RuntimeException.class)); 143 | return this; 144 | } 145 | 146 | /** 147 | * Configures the retryer to retry if an exception of the given class (or subclass of the given class) is 148 | * thrown by the call. 149 | * 150 | * @param exceptionClass the type of the exception which should cause the retryer to retry 151 | * @return this 152 | */ 153 | public RetryerBuilder retryIfExceptionOfType(@Nonnull Class exceptionClass) { 154 | Preconditions.checkNotNull(exceptionClass, "exceptionClass may not be null"); 155 | retryPredicates.add(new ExceptionClassPredicate(exceptionClass)); 156 | return this; 157 | } 158 | 159 | /** 160 | * Configures the retryer to retry if an exception satisfying the given predicate is 161 | * thrown by the call. 162 | * 163 | * @param exceptionPredicate the predicate which causes a retry if satisfied 164 | * @return this 165 | */ 166 | public RetryerBuilder retryIfException(@Nonnull Predicate exceptionPredicate) { 167 | Preconditions.checkNotNull(exceptionPredicate, "exceptionPredicate may not be null"); 168 | retryPredicates.add(new ExceptionPredicate(exceptionPredicate)); 169 | return this; 170 | } 171 | 172 | /** 173 | * Configures the retryer to retry if the result satisfies the given predicate. 174 | * 175 | * @param The type of object tested by the predicate 176 | * @param resultPredicate a predicate applied to the result, and which causes the retryer 177 | * to retry if the predicate is satisfied 178 | * @return this 179 | */ 180 | public RetryerBuilder retryIfResult(@Nonnull Predicate resultPredicate) { 181 | Preconditions.checkNotNull(resultPredicate, "resultPredicate may not be null"); 182 | retryPredicates.add(new ResultPredicate<>(resultPredicate)); 183 | return this; 184 | } 185 | 186 | /** 187 | * Builds the retryer. 188 | * 189 | * @return the built retryer. 190 | */ 191 | public Retryer build() { 192 | AttemptTimeLimiter theAttemptTimeLimiter = attemptTimeLimiter == null ? AttemptTimeLimiters.noTimeLimit() : attemptTimeLimiter; 193 | StopStrategy theStopStrategy = stopStrategy == null ? StopStrategies.neverStop() : stopStrategy; 194 | WaitStrategy theWaitStrategy = waitStrategy == null ? WaitStrategies.noWait() : waitStrategy; 195 | BlockStrategy theBlockStrategy = blockStrategy == null ? BlockStrategies.threadSleepStrategy() : blockStrategy; 196 | 197 | return new Retryer( 198 | theAttemptTimeLimiter, 199 | theStopStrategy, 200 | theWaitStrategy, 201 | theBlockStrategy, 202 | retryPredicates, 203 | listeners); 204 | } 205 | 206 | private static final class ExceptionClassPredicate implements Predicate> { 207 | 208 | private Class exceptionClass; 209 | 210 | ExceptionClassPredicate(Class exceptionClass) { 211 | this.exceptionClass = exceptionClass; 212 | } 213 | 214 | @Override 215 | public boolean test(Attempt attempt) { 216 | return attempt.hasException() && 217 | exceptionClass.isAssignableFrom(attempt.getException().getClass()); 218 | } 219 | } 220 | 221 | private static final class ResultPredicate implements Predicate> { 222 | 223 | private Predicate delegate; 224 | 225 | ResultPredicate(Predicate delegate) { 226 | this.delegate = delegate; 227 | } 228 | 229 | @Override 230 | public boolean test(Attempt attempt) { 231 | if (!attempt.hasResult()) { 232 | return false; 233 | } 234 | try { 235 | @SuppressWarnings("unchecked") 236 | T result = (T) attempt.getResult(); 237 | return delegate.test(result); 238 | } catch (ClassCastException e) { 239 | return false; 240 | } 241 | } 242 | } 243 | 244 | private static final class ExceptionPredicate implements Predicate> { 245 | 246 | private Predicate delegate; 247 | 248 | ExceptionPredicate(Predicate delegate) { 249 | this.delegate = delegate; 250 | } 251 | 252 | @Override 253 | public boolean test(Attempt attempt) { 254 | return attempt.hasException() && delegate.test(attempt.getException()); 255 | } 256 | } 257 | } 258 | -------------------------------------------------------------------------------- /docs/com/github/rholder/retry/Retryer.RetryerCallable.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Retryer.RetryerCallable (re-retrying 3.0.1-SNAPSHOT API) 7 | 8 | 9 | 10 | 11 | 12 | 28 |

JavaScript is disabled on your browser.
30 | 31 | 32 |
33 | 34 | 35 | 36 | 37 | 38 | 39 | 47 |
48 | 90 | 91 | 92 |
93 |
com.github.rholder.retry
94 |

Class Retryer.RetryerCallable<X>

95 |
96 |
97 |
    98 |
  • java.lang.Object
  • 99 |
  • 100 |
      101 |
    • com.github.rholder.retry.Retryer.RetryerCallable<X>
    • 102 |
    103 |
  • 104 |
105 |
106 |
    107 |
  • 108 |
    109 |
    All Implemented Interfaces:
    110 |
    java.util.concurrent.Callable<X>
    111 |
    112 |
    113 |
    Enclosing class:
    114 |
    Retryer<V>
    115 |
    116 |
    117 |
    118 |
    public static class Retryer.RetryerCallable<X>
    119 | extends java.lang.Object
    120 | implements java.util.concurrent.Callable<X>
    121 |
    A Callable which wraps another Callable in order to add 122 | retrying behavior from a given Retryer instance.
    123 |
  • 124 |
125 |
126 |
127 |
    128 |
  • 129 | 130 |
      131 |
    • 132 | 133 | 134 |

      Method Summary

      135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 146 | 147 |
      All Methods Instance Methods Concrete Methods 
      Modifier and TypeMethod and Description
      Xcall() 144 |
      Makes the enclosing retryer call the wrapped callable.
      145 |
      148 |
        149 |
      • 150 | 151 | 152 |

        Methods inherited from class java.lang.Object

        153 | clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
      • 154 |
      155 |
    • 156 |
    157 |
  • 158 |
159 |
160 |
161 |
    162 |
  • 163 | 164 |
      165 |
    • 166 | 167 | 168 |

      Method Detail

      169 | 170 | 171 | 172 |
        173 |
      • 174 |

        call

        175 |
        public X call()
        176 |        throws java.util.concurrent.ExecutionException,
        177 |               RetryException
        178 |
        Makes the enclosing retryer call the wrapped callable.
        179 |
        180 |
        Specified by:
        181 |
        call in interface java.util.concurrent.Callable<X>
        182 |
        Throws:
        183 |
        java.util.concurrent.ExecutionException
        184 |
        RetryException
        185 |
        See Also:
        186 |
        Retryer.call(Callable)
        187 |
        188 |
      • 189 |
      190 |
    • 191 |
    192 |
  • 193 |
194 |
195 |
196 | 197 | 198 |
199 | 200 | 201 | 202 | 203 | 204 | 205 | 213 |
214 | 256 | 257 | 258 | 259 | -------------------------------------------------------------------------------- /docs/com/github/rholder/retry/package-summary.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | com.github.rholder.retry (re-retrying 3.0.1-SNAPSHOT API) 7 | 8 | 9 | 10 | 11 | 12 | 22 | 25 | 26 |
27 | 28 | 29 | 30 | 31 | 32 | 33 | 41 |
42 | 69 | 70 |
71 |

Package com.github.rholder.retry

72 |
73 |
74 |
    75 |
  • 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 89 | 90 | 91 | 92 | 95 | 96 | 97 | 98 | 102 | 103 | 104 | 105 | 109 | 110 | 111 | 112 | 115 | 116 | 117 | 118 | 121 | 122 | 123 |
    Interface Summary 
    InterfaceDescription
    Attempt<V> 86 |
    An attempt of a call, which resulted either in a result returned by the call, 87 | or in a Throwable thrown by the call.
    88 |
    AttemptTimeLimiter<V> 93 |
    A rule to wrap any single attempt in a time limit, where it will possibly be interrupted if the limit is exceeded.
    94 |
    BlockStrategy 99 |
    This is a strategy used to decide how a retryer should block between retry 100 | attempts.
    101 |
    RetryListener 106 |
    This listener provides callbacks for several events that occur when running 107 | code through a Retryer instance.
    108 |
    StopStrategy 113 |
    A strategy used to decide if a retryer must stop retrying after a failed attempt or not.
    114 |
    WaitStrategy 119 |
    A strategy used to decide how long to sleep before retrying after a failed attempt.
    120 |
    124 |
  • 125 |
  • 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 138 | 139 | 140 | 141 | 144 | 145 | 146 | 147 | 151 | 152 | 153 | 154 | 158 | 159 | 160 | 161 | 164 | 165 | 166 | 167 | 170 | 171 | 172 | 173 | 176 | 177 | 178 |
    Class Summary 
    ClassDescription
    AttemptTimeLimiters 136 |
    Factory class for instances of AttemptTimeLimiter
    137 |
    BlockStrategies 142 |
    Factory class for BlockStrategy instances.
    143 |
    Retryer<V> 148 |
    A retryer, which executes a call, and retries it until it succeeds, or 149 | a stop strategy decides to stop retrying.
    150 |
    Retryer.RetryerCallable<X> 155 |
    A Callable which wraps another Callable in order to add 156 | retrying behavior from a given Retryer instance.
    157 |
    RetryerBuilder<V> 162 |
    A builder used to configure and create a Retryer.
    163 |
    StopStrategies 168 |
    Factory class for StopStrategy instances.
    169 |
    WaitStrategies 174 |
    Factory class for instances of WaitStrategy.
    175 |
    179 |
  • 180 |
  • 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 194 | 195 | 196 |
    Exception Summary 
    ExceptionDescription
    RetryException 191 |
    An exception indicating that none of the attempts of the Retryer 192 | succeeded.
    193 |
    197 |
  • 198 |
199 |
200 | 201 |
202 | 203 | 204 | 205 | 206 | 207 | 208 | 216 |
217 | 244 | 245 | 246 | 247 | -------------------------------------------------------------------------------- /docs/com/github/rholder/retry/RetryException.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | RetryException (re-retrying 3.0.1-SNAPSHOT API) 7 | 8 | 9 | 10 | 11 | 12 | 28 | 31 | 32 |
33 | 34 | 35 | 36 | 37 | 38 | 39 | 47 |
48 | 90 | 91 | 92 |
93 |
com.github.rholder.retry
94 |

Class RetryException

95 |
96 |
97 |
    98 |
  • java.lang.Object
  • 99 |
  • 100 |
      101 |
    • java.lang.Throwable
    • 102 |
    • 103 |
        104 |
      • java.lang.Exception
      • 105 |
      • 106 |
          107 |
        • com.github.rholder.retry.RetryException
        • 108 |
        109 |
      • 110 |
      111 |
    • 112 |
    113 |
  • 114 |
115 |
116 |
    117 |
  • 118 |
    119 |
    All Implemented Interfaces:
    120 |
    java.io.Serializable
    121 |
    122 |
    123 |
    124 |
    @Immutable
    125 | public final class RetryException
    126 | extends java.lang.Exception
    127 |
    An exception indicating that none of the attempts of the Retryer 128 | succeeded. If the last Attempt resulted in an Exception, it is set as 129 | the cause of the RetryException.
    130 |
    131 |
    See Also:
    132 |
    Serialized Form
    133 |
    134 |
  • 135 |
136 |
137 |
138 |
    139 |
  • 140 | 141 |
      142 |
    • 143 | 144 | 145 |

      Method Summary

      146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 157 | 158 | 159 | 160 | 163 | 164 |
      All Methods Instance Methods Concrete Methods 
      Modifier and TypeMethod and Description
      Attempt<?>getLastFailedAttempt() 155 |
      Returns the last failed attempt
      156 |
      intgetNumberOfFailedAttempts() 161 |
      Returns the number of failed attempts
      162 |
      165 |
        166 |
      • 167 | 168 | 169 |

        Methods inherited from class java.lang.Throwable

        170 | addSuppressed, fillInStackTrace, getCause, getLocalizedMessage, getMessage, getStackTrace, getSuppressed, initCause, printStackTrace, printStackTrace, printStackTrace, setStackTrace, toString
      • 171 |
      172 |
        173 |
      • 174 | 175 | 176 |

        Methods inherited from class java.lang.Object

        177 | clone, equals, finalize, getClass, hashCode, notify, notifyAll, wait, wait, wait
      • 178 |
      179 |
    • 180 |
    181 |
  • 182 |
183 |
184 |
185 |
    186 |
  • 187 | 188 |
      189 |
    • 190 | 191 | 192 |

      Method Detail

      193 | 194 | 195 | 196 |
        197 |
      • 198 |

        getNumberOfFailedAttempts

        199 |
        public int getNumberOfFailedAttempts()
        200 |
        Returns the number of failed attempts
        201 |
        202 |
        Returns:
        203 |
        the number of failed attempts
        204 |
        205 |
      • 206 |
      207 | 208 | 209 | 210 |
        211 |
      • 212 |

        getLastFailedAttempt

        213 |
        public Attempt<?> getLastFailedAttempt()
        214 |
        Returns the last failed attempt
        215 |
        216 |
        Returns:
        217 |
        the last failed attempt
        218 |
        219 |
      • 220 |
      221 |
    • 222 |
    223 |
  • 224 |
225 |
226 |
227 | 228 | 229 |
230 | 231 | 232 | 233 | 234 | 235 | 236 | 244 |
245 | 287 | 288 | 289 | 290 | --------------------------------------------------------------------------------