From 3027a510209ef6d2e64576803a97a1c477f6f07d Mon Sep 17 00:00:00 2001 From: qct Date: Wed, 22 Mar 2017 20:09:10 +0800 Subject: [PATCH 1/3] add Runnable --- .../com/github/rholder/retry/Retryer.java | 78 +++++++++++++++++++ .../rholder/retry/RetryerBuilderTest.java | 17 ++++ 2 files changed, 95 insertions(+) diff --git a/src/main/java/com/github/rholder/retry/Retryer.java b/src/main/java/com/github/rholder/retry/Retryer.java index eaff3ef..147fa7a 100644 --- a/src/main/java/com/github/rholder/retry/Retryer.java +++ b/src/main/java/com/github/rholder/retry/Retryer.java @@ -184,6 +184,38 @@ public V call(Callable callable) throws ExecutionException, RetryException { } } + public void run(Runnable runnable) throws ExecutionException, RetryException { + long startTime = System.nanoTime(); + for (int attemptNumber = 1; ; attemptNumber++) { + Attempt attempt; + try { + runnable.run(); + attempt = new VoidResultAttempt(attemptNumber, TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - startTime)); + } catch (Throwable t) { + attempt = new ExceptionAttempt(t, attemptNumber, TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - startTime)); + } + + for (RetryListener listener : listeners) { + listener.onRetry(attempt); + } + + if (!rejectionPredicate.apply(attempt)) { + return; + } + if (stopStrategy.shouldStop(attempt)) { + throw new RetryException(attemptNumber, attempt); + } else { + long sleepTime = waitStrategy.computeSleepTime(attempt); + try { + blockStrategy.block(sleepTime); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + throw new RetryException(attemptNumber, attempt); + } + } + } + } + /** * Wraps the given {@link Callable} in a {@link RetryerCallable}, which can * be submitted to an executor. The returned {@link RetryerCallable} uses @@ -292,6 +324,52 @@ public long getDelaySinceFirstAttempt() { } } + @Immutable + static final class VoidResultAttempt implements Attempt { + private final long attemptNumber; + private final long delaySinceFirstAttempt; + + public VoidResultAttempt(long attemptNumber, long delaySinceFirstAttempt) { + this.attemptNumber = attemptNumber; + this.delaySinceFirstAttempt = delaySinceFirstAttempt; + } + + @Override + public Void get() throws ExecutionException { + return null; + } + + @Override + public boolean hasResult() { + return false; + } + + @Override + public boolean hasException() { + return false; + } + + @Override + public Void getResult() throws IllegalStateException { + throw new IllegalStateException("The attempt resulted in a void result"); + } + + @Override + public Throwable getExceptionCause() throws IllegalStateException { + throw new IllegalStateException("The attempt resulted in a void result, not in an exception"); + } + + @Override + public long getAttemptNumber() { + return attemptNumber; + } + + @Override + public long getDelaySinceFirstAttempt() { + return delaySinceFirstAttempt; + } + } + /** * A {@link Callable} which wraps another {@link Callable} in order to add * retrying behavior from a given {@link Retryer} instance. diff --git a/src/test/java/com/github/rholder/retry/RetryerBuilderTest.java b/src/test/java/com/github/rholder/retry/RetryerBuilderTest.java index 9849b96..f12279c 100644 --- a/src/test/java/com/github/rholder/retry/RetryerBuilderTest.java +++ b/src/test/java/com/github/rholder/retry/RetryerBuilderTest.java @@ -571,4 +571,21 @@ public Boolean call() throws Exception { } }; } + + @Test + public void testRunnable() throws Exception { + Runnable runnable = new Runnable() { + @Override + public void run() { + System.out.println("I'm running"); + } + }; + + Retryer retryer = RetryerBuilder.newBuilder() + .withStopStrategy(StopStrategies.stopAfterAttempt(3)) + .retryIfRuntimeException() + .build(); + + retryer.run(runnable); + } } From 517b9c8395afacf27a1308c094a4f4bf85e02e2d Mon Sep 17 00:00:00 2001 From: qct Date: Thu, 23 Mar 2017 11:13:09 +0800 Subject: [PATCH 2/3] add retrying of Runnable --- .../com/github/rholder/retry/Retryer.java | 90 +++++++++++++++++-- .../rholder/retry/RetryerBuilderTest.java | 26 ++++++ 2 files changed, 107 insertions(+), 9 deletions(-) diff --git a/src/main/java/com/github/rholder/retry/Retryer.java b/src/main/java/com/github/rholder/retry/Retryer.java index eaff3ef..25cc318 100644 --- a/src/main/java/com/github/rholder/retry/Retryer.java +++ b/src/main/java/com/github/rholder/retry/Retryer.java @@ -170,16 +170,42 @@ public V call(Callable callable) throws ExecutionException, RetryException { if (!rejectionPredicate.apply(attempt)) { return attempt.get(); } - if (stopStrategy.shouldStop(attempt)) { + stopOrBlock(attemptNumber, attempt); + } + } + + public void run(Runnable runnable) throws ExecutionException, RetryException { + long startTime = System.nanoTime(); + for (int attemptNumber = 1; ; attemptNumber++) { + Attempt attempt; + try { + runnable.run(); + attempt = new VoidResultAttempt(attemptNumber, TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - startTime)); + } catch (Throwable t) { + attempt = new ExceptionAttempt(t, attemptNumber, TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - startTime)); + } + + for (RetryListener listener : listeners) { + listener.onRetry(attempt); + } + + if (!rejectionPredicate.apply(attempt)) { + return; + } + stopOrBlock(attemptNumber, attempt); + } + } + + private void stopOrBlock(int attemptNumber, Attempt attempt) throws RetryException { + if (stopStrategy.shouldStop(attempt)) { + throw new RetryException(attemptNumber, attempt); + } else { + long sleepTime = waitStrategy.computeSleepTime(attempt); + try { + blockStrategy.block(sleepTime); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); throw new RetryException(attemptNumber, attempt); - } else { - long sleepTime = waitStrategy.computeSleepTime(attempt); - try { - blockStrategy.block(sleepTime); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - throw new RetryException(attemptNumber, attempt); - } } } } @@ -292,6 +318,52 @@ public long getDelaySinceFirstAttempt() { } } + @Immutable + static final class VoidResultAttempt implements Attempt { + private final long attemptNumber; + private final long delaySinceFirstAttempt; + + public VoidResultAttempt(long attemptNumber, long delaySinceFirstAttempt) { + this.attemptNumber = attemptNumber; + this.delaySinceFirstAttempt = delaySinceFirstAttempt; + } + + @Override + public Void get() throws ExecutionException { + throw new IllegalStateException("The attempt resulted in a void result"); + } + + @Override + public boolean hasResult() { + return false; + } + + @Override + public boolean hasException() { + return false; + } + + @Override + public Void getResult() throws IllegalStateException { + throw new IllegalStateException("The attempt resulted in a void result"); + } + + @Override + public Throwable getExceptionCause() throws IllegalStateException { + throw new IllegalStateException("The attempt resulted in a void result, not in an exception"); + } + + @Override + public long getAttemptNumber() { + return attemptNumber; + } + + @Override + public long getDelaySinceFirstAttempt() { + return delaySinceFirstAttempt; + } + } + /** * A {@link Callable} which wraps another {@link Callable} in order to add * retrying behavior from a given {@link Retryer} instance. diff --git a/src/test/java/com/github/rholder/retry/RetryerBuilderTest.java b/src/test/java/com/github/rholder/retry/RetryerBuilderTest.java index 9849b96..1f02a53 100644 --- a/src/test/java/com/github/rholder/retry/RetryerBuilderTest.java +++ b/src/test/java/com/github/rholder/retry/RetryerBuilderTest.java @@ -571,4 +571,30 @@ public Boolean call() throws Exception { } }; } + + @Test + public void testRunnable() throws Exception { + Runnable runnable = new Runnable() { + @Override + public void run() { + throw new NullPointerException(); + } + }; + + Retryer retryer = RetryerBuilder.newBuilder() + .retryIfRuntimeException() + .withStopStrategy(StopStrategies.stopAfterAttempt(3)) + .retryIfRuntimeException() + .build(); + + try { + retryer.run(runnable); + fail("RetryException expected"); + } catch (RetryException e) { + assertEquals(3, e.getNumberOfFailedAttempts()); + assertTrue(e.getLastFailedAttempt().hasException()); + assertTrue(e.getLastFailedAttempt().getExceptionCause() instanceof NullPointerException); + assertTrue(e.getCause() instanceof NullPointerException); + } + } } From 2af7b3fefa2638d0dbe0f1407192a63c3a229038 Mon Sep 17 00:00:00 2001 From: qct Date: Thu, 23 Mar 2017 11:52:43 +0800 Subject: [PATCH 3/3] change dependency of guava to a fixed version of 20.0 --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 210cecb..ed1d9a5 100644 --- a/build.gradle +++ b/build.gradle @@ -81,7 +81,7 @@ repositories { } dependencies { - compile 'com.google.guava:guava:[10.+,)' + compile 'com.google.guava:guava:20.0' compile 'com.google.code.findbugs:jsr305:2.0.2' // junit testing