public <T> T runWithRetries(RetryableDockerOperation<T> operation) throws IOException, InterruptedException { DockerExecutionException lastExecutionException = null; for (int i = 0; i <= retryAttempts; i++) { try { return operation.call(); } catch (DockerExecutionException e) { lastExecutionException = e; log.warn("Caught exception: {}", e.getMessage()); log.warn("Retrying after {}", delay); if (i < retryAttempts) { Thread.sleep(delay.getMillis()); } } } log.error("Exhausted all retry attempts. Tried {} times.", retryAttempts); throw lastExecutionException; } }
public <T> T runWithRetries(RetryableDockerOperation<T> operation) throws IOException, InterruptedException { DockerExecutionException lastExecutionException = null; for (int i = 0; i <= retryAttempts; i++) { try { return operation.call(); } catch (DockerExecutionException e) { lastExecutionException = e; log.warn("Caught exception: {}. Retrying after {}", e.getMessage(), delay); if (i < retryAttempts) { Thread.sleep(delay.getMillis()); } } } throw lastExecutionException; } }
public <T> T runWithRetries(RetryableDockerOperation<T> operation) throws IOException, InterruptedException { DockerExecutionException lastExecutionException = null; for (int i = 0; i <= retryAttempts; i++) { try { return operation.call(); } catch (DockerExecutionException e) { lastExecutionException = e; log.warn("Caught exception: {}. Retrying after {}", e.getMessage(), delay); if (i < retryAttempts) { Thread.sleep(delay.getMillis()); } } } throw lastExecutionException; } }
@Test public void throw_the_last_exception_when_the_operation_fails_more_times_than_the_number_of_specified_retry_attempts() throws Exception { DockerExecutionException finalException = new DockerExecutionException(); when(operation.call()).thenAnswer(MockitoMultiAnswer.<String>of( firstInvocation -> { throw new DockerExecutionException(); }, secondInvocation -> { throw finalException; } )); try { retryer.runWithRetries(operation); fail("Should have caught exception"); } catch (DockerExecutionException actualException) { assertThat(actualException, is(finalException)); } verify(operation, times(2)).call(); } }
private void retryerJustCallsOperation() throws IOException, InterruptedException { when(retryer.runWithRetries(anyOperation())).thenAnswer(invocation -> { Retryer.RetryableDockerOperation<?> operation = (Retryer.RetryableDockerOperation<?>) invocation.getArguments()[0]; return operation.call(); }); }
@Test public void retry_the_operation_if_it_failed_once_and_return_the_result_of_the_next_successful_call() throws Exception { when(operation.call()).thenAnswer(MockitoMultiAnswer.<String>of( firstInvocation -> { throw new DockerExecutionException(); }, secondInvocation -> "hola" )); assertThat(retryer.runWithRetries(operation), is("hola")); verify(operation, times(2)).call(); }
@Test public void should_not_pause_after_last_failure() throws Exception { Retryer failFast = new Retryer(0, Duration.standardSeconds(1)); when(operation.call()).thenThrow(new DockerExecutionException()); Stopwatch stopwatch = Stopwatch.createStarted(); try { failFast.runWithRetries(operation); } catch (DockerExecutionException e) { // expected } assertThat(stopwatch.elapsed(TimeUnit.MILLISECONDS), lessThan(1000L)); }
@Test public void retryer_should_wait_after_failure_before_trying_again() throws Exception { Retryer timeRetryer = new Retryer(1, Duration.millis(100)); Stopwatch stopwatch = Stopwatch.createStarted(); when(operation.call()).thenThrow(new DockerExecutionException()).thenAnswer(i -> { assertThat(stopwatch.elapsed(TimeUnit.MILLISECONDS), greaterThan(100L)); return "success"; }); String result = timeRetryer.runWithRetries(operation); assertThat(result, is("success")); }