@Test public void testCancelByRetryingAlgorithm() throws Exception { FailingCallable callable = new FailingCallable(6, "FAILURE", tracer); RetryingExecutorWithContext<String> executor = getExecutor(getAlgorithm(FAST_RETRY_SETTINGS, 5, new CancellationException())); RetryingFuture<String> future = executor.createFuture(callable, retryingContext); future.setAttemptFuture(executor.submit(future)); assertFutureCancel(future); assertEquals(4, future.getAttemptSettings().getAttemptCount()); verify(tracer, times(5)).attemptStarted(anyInt()); // Pre-apocalypse failures verify(tracer, times(4)).attemptFailed(any(Throwable.class), any(Duration.class)); // Apocalypse failure verify(tracer, times(1)).attemptFailedRetriesExhausted(any(CancellationException.class)); verifyNoMoreInteractions(tracer); }
@Override public RetryingFuture<ResponseT> futureCall(RequestT ignored, ApiCallContext inputContext) { CheckingAttemptCallable<RequestT, ResponseT> checkingAttemptCallable = new CheckingAttemptCallable<>(callable, inputContext); RetryingFuture<ResponseT> retryingFuture = executor.createFuture(checkingAttemptCallable, inputContext); checkingAttemptCallable.setExternalFuture(retryingFuture); checkingAttemptCallable.call(); return retryingFuture; }
@Override public RetryingFuture<ResponseT> futureCall(RequestT ignored, ApiCallContext inputContext) { CheckingAttemptCallable<RequestT, ResponseT> checkingAttemptCallable = new CheckingAttemptCallable<>(callable, inputContext); RetryingFuture<ResponseT> retryingFuture = executor.createFuture(checkingAttemptCallable, inputContext); checkingAttemptCallable.setExternalFuture(retryingFuture); checkingAttemptCallable.call(); return retryingFuture; }
@Test public void testMaxRetriesExceeded() throws Exception { FailingCallable callable = new FailingCallable(6, "FAILURE", tracer); RetryingExecutorWithContext<String> executor = getExecutor(getAlgorithm(FAST_RETRY_SETTINGS, 0, null)); RetryingFuture<String> future = executor.createFuture(callable, retryingContext); future.setAttemptFuture(executor.submit(future)); assertFutureFail(future, CustomException.class); assertEquals(5, future.getAttemptSettings().getAttemptCount()); verify(tracer, times(6)).attemptStarted(anyInt()); verify(tracer, times(5)).attemptFailed(any(Throwable.class), any(Duration.class)); verify(tracer, times(1)).attemptFailedRetriesExhausted(any(Throwable.class)); verifyNoMoreInteractions(tracer); }
@Override public RetryingFuture<ResponseT> futureCall(RequestT request, ApiCallContext inputContext) { ApiCallContext context = callContextPrototype.nullToSelf(inputContext); AttemptCallable<RequestT, ResponseT> retryCallable = new AttemptCallable<>(callable, request, context); RetryingFuture<ResponseT> retryingFuture = executor.createFuture(retryCallable, inputContext); retryCallable.setExternalFuture(retryingFuture); retryCallable.call(); return retryingFuture; }
@Test public void testSuccessWithFailures() throws Exception { FailingCallable callable = new FailingCallable(5, "SUCCESS", tracer); RetryingExecutorWithContext<String> executor = getExecutor(getAlgorithm(FAST_RETRY_SETTINGS, 0, null)); RetryingFuture<String> future = executor.createFuture(callable, retryingContext); future.setAttemptFuture(executor.submit(future)); assertFutureSuccess(future); assertEquals(5, future.getAttemptSettings().getAttemptCount()); verify(tracer, times(6)).attemptStarted(anyInt()); verify(tracer, times(5)).attemptFailed(any(Throwable.class), any(Duration.class)); verify(tracer, times(1)).attemptSucceeded(); verifyNoMoreInteractions(tracer); }
@Override public RetryingFuture<ResponseT> futureCall(RequestT request, ApiCallContext inputContext) { ApiCallContext context = callContextPrototype.nullToSelf(inputContext); AttemptCallable<RequestT, ResponseT> retryCallable = new AttemptCallable<>(callable, request, context); RetryingFuture<ResponseT> retryingFuture = executor.createFuture(retryCallable, inputContext); retryCallable.setExternalFuture(retryingFuture); retryCallable.call(); return retryingFuture; }
@Test public void testUnexpectedExceptionFromRetryAlgorithm() throws Exception { FailingCallable callable = new FailingCallable(6, "FAILURE", tracer); RetryingExecutorWithContext<String> executor = getExecutor(getAlgorithm(FAST_RETRY_SETTINGS, 5, new RuntimeException())); RetryingFuture<String> future = executor.createFuture(callable, retryingContext); future.setAttemptFuture(executor.submit(future)); assertFutureFail(future, RuntimeException.class); assertEquals(4, future.getAttemptSettings().getAttemptCount()); verify(tracer, times(5)).attemptStarted(anyInt()); // Pre-apocalypse failures verify(tracer, times(4)).attemptFailed(any(Throwable.class), any(Duration.class)); // Apocalypse failure verify(tracer, times(1)).attemptPermanentFailure(any(RuntimeException.class)); verifyNoMoreInteractions(tracer); }
@Test public void testSuccess() throws Exception { FailingCallable callable = new FailingCallable(0, "SUCCESS", tracer); RetryingExecutorWithContext<String> executor = getExecutor(getAlgorithm(FAST_RETRY_SETTINGS, 0, null)); RetryingFuture<String> future = executor.createFuture(callable, retryingContext); future.setAttemptFuture(executor.submit(future)); assertFutureSuccess(future); assertEquals(0, future.getAttemptSettings().getAttemptCount()); verify(tracer, times(1)).attemptStarted(0); verify(tracer, times(1)).attemptSucceeded(); verifyNoMoreInteractions(tracer); }
@Test public void testTotalTimeoutExceeded() throws Exception { RetrySettings retrySettings = FAST_RETRY_SETTINGS .toBuilder() .setInitialRetryDelay(Duration.ofMillis(Integer.MAX_VALUE)) .setMaxRetryDelay(Duration.ofMillis(Integer.MAX_VALUE)) .build(); RetryingExecutorWithContext<String> executor = getExecutor(getAlgorithm(retrySettings, 0, null)); FailingCallable callable = new FailingCallable(6, "FAILURE", tracer); RetryingFuture<String> future = executor.createFuture(callable, retryingContext); future.setAttemptFuture(executor.submit(future)); assertFutureFail(future, CustomException.class); assertTrue(future.getAttemptSettings().getAttemptCount() < 4); verify(tracer, times(1)).attemptStarted(anyInt()); verify(tracer, times(1)).attemptFailedRetriesExhausted(any(Throwable.class)); verifyNoMoreInteractions(tracer); }
@Test public void testPollExceptionByPollAlgorithm() throws Exception { RetrySettings retrySettings = FAST_RETRY_SETTINGS .toBuilder() .setInitialRetryDelay(Duration.ofMillis(Integer.MAX_VALUE)) .setMaxRetryDelay(Duration.ofMillis(Integer.MAX_VALUE)) .build(); RetryAlgorithm<String> retryAlgorithm = new RetryAlgorithm<>( new TestResultRetryAlgorithm<String>(0, null), new ExponentialPollAlgorithm(retrySettings, NanoClock.getDefaultClock())); RetryingExecutorWithContext<String> executor = getExecutor(retryAlgorithm); FailingCallable callable = new FailingCallable(6, "FAILURE", tracer); RetryingFuture<String> future = executor.createFuture(callable, retryingContext); future.setAttemptFuture(executor.submit(future)); assertFutureFail(future, PollException.class); assertTrue(future.getAttemptSettings().getAttemptCount() < 4); verify(tracer, times(1)).attemptStarted(anyInt()); verify(tracer, times(1)).attemptPermanentFailure(any(PollException.class)); verifyNoMoreInteractions(tracer); }
RetryingFuture<String> future = executor.createFuture(callable, retryingContext); assertFalse(future.getAttemptResult().isCancelled()); future.setAttemptFuture(executor.submit(future));
@Test public void testSuccessWithFailuresPeekGetAttempt() throws Exception { FailingCallable callable = new FailingCallable(5, "SUCCESS", tracer); RetryingExecutorWithContext<String> executor = getExecutor(getAlgorithm(FAST_RETRY_SETTINGS, 0, null)); RetryingFuture<String> future = executor.createFuture(callable, retryingContext); assertNull(future.peekAttemptResult()); assertSame(future.peekAttemptResult(), future.peekAttemptResult()); assertFalse(future.getAttemptResult().isDone()); assertFalse(future.getAttemptResult().isCancelled()); Exception exception = null; try { future.get(1L, TimeUnit.MILLISECONDS); } catch (TimeoutException e) { exception = e; } assertNotNull(exception); future.setAttemptFuture(executor.submit(future)); assertFutureSuccess(future); assertEquals(5, future.getAttemptSettings().getAttemptCount()); }
RetryingFuture<String> future = executor.createFuture(callable, retryingContext); assertFalse(future.getAttemptResult().isCancelled()); future.setAttemptFuture(executor.submit(future));
RetryingFuture<String> future = executor.createFuture(callable, retryingContext); assertFalse(future.getAttemptResult().isCancelled()); future.setAttemptFuture(executor.submit(future));