return settings; RetrySettings.Builder builder = settings.toBuilder(); for (RetryOption option : options) { switch (option.type) {
retrySettings = retrySettings.toBuilder().setMaxAttempts(Integer.MAX_VALUE).build();
defRetrySettings.toBuilder().setTotalTimeout(Duration.ofMillis(420L)).build(); mergedRetrySettings = RetryOption.mergeToSettings(defRetrySettings, TOTAL_TIMEOUT); assertEquals(defRetrySettings, mergedRetrySettings); defRetrySettings.toBuilder().setMaxRetryDelay(Duration.ofMillis(100)).build(); mergedRetrySettings = RetryOption.mergeToSettings(defRetrySettings, MAX_RETRY_DELAY); assertEquals(defRetrySettings, mergedRetrySettings); defRetrySettings.toBuilder().setInitialRetryDelay(Duration.ofMillis(42L)).build(); mergedRetrySettings = RetryOption.mergeToSettings(defRetrySettings, INITIAL_RETRY_DELAY); assertEquals(defRetrySettings, mergedRetrySettings); defRetrySettings = defRetrySettings.toBuilder().setRetryDelayMultiplier(1.5).build(); mergedRetrySettings = RetryOption.mergeToSettings(defRetrySettings, RETRY_DELAY_MULTIPLIER); assertEquals(defRetrySettings, mergedRetrySettings); defRetrySettings = defRetrySettings.toBuilder().setMaxAttempts(100).build(); mergedRetrySettings = RetryOption.mergeToSettings(defRetrySettings, MAX_ATTEMPTS); assertEquals(defRetrySettings, mergedRetrySettings); defRetrySettings = defRetrySettings.toBuilder().setJittered(false).build(); mergedRetrySettings = RetryOption.mergeToSettings(defRetrySettings, JITTERED); assertEquals(defRetrySettings, mergedRetrySettings);
@Test public void testPublishFailureRetries_maxRetriesSetUnlimited() throws Exception { Publisher publisher = getTestPublisherBuilder() .setExecutorProvider(SINGLE_THREAD_EXECUTOR) .setRetrySettings( Publisher.Builder.DEFAULT_RETRY_SETTINGS .toBuilder() .setTotalTimeout(Duration.ofSeconds(10)) .setMaxAttempts(0) .build()) .build(); testPublisherServiceImpl.addPublishError(new Throwable("Transiently failing")); testPublisherServiceImpl.addPublishError(new Throwable("Transiently failing")); testPublisherServiceImpl.addPublishResponse(PublishResponse.newBuilder().addMessageIds("1")); ApiFuture<String> publishFuture1 = sendTestMessage(publisher, "A"); assertEquals("1", publishFuture1.get()); assertEquals(3, testPublisherServiceImpl.getCapturedRequests().size()); publisher.shutdown(); publisher.awaitTermination(1, TimeUnit.MINUTES); }
@Test(expected = ExecutionException.class) public void testPublishFailureRetries_retriesDisabled() throws Exception { Publisher publisher = getTestPublisherBuilder() .setExecutorProvider(SINGLE_THREAD_EXECUTOR) .setRetrySettings( Publisher.Builder.DEFAULT_RETRY_SETTINGS .toBuilder() .setTotalTimeout(Duration.ofSeconds(10)) .setMaxAttempts(1) .build()) .build(); testPublisherServiceImpl.addPublishError(new Throwable("Transiently failing")); ApiFuture<String> publishFuture1 = sendTestMessage(publisher, "A"); try { publishFuture1.get(); } finally { assertSame(testPublisherServiceImpl.getCapturedRequests().size(), 1); publisher.shutdown(); publisher.awaitTermination(1, TimeUnit.MINUTES); } }
@Test public void testPublishFailureRetries_maxRetriesSetup() throws Exception { Publisher publisher = getTestPublisherBuilder() .setExecutorProvider(SINGLE_THREAD_EXECUTOR) .setRetrySettings( Publisher.Builder.DEFAULT_RETRY_SETTINGS .toBuilder() .setTotalTimeout(Duration.ofSeconds(10)) .setMaxAttempts(3) .build()) .build(); testPublisherServiceImpl.addPublishError(new Throwable("Transiently failing")); testPublisherServiceImpl.addPublishError(new Throwable("Transiently failing")); testPublisherServiceImpl.addPublishResponse(PublishResponse.newBuilder().addMessageIds("1")); ApiFuture<String> publishFuture1 = sendTestMessage(publisher, "A"); assertEquals("1", publishFuture1.get()); assertEquals(3, testPublisherServiceImpl.getCapturedRequests().size()); publisher.shutdown(); publisher.awaitTermination(1, TimeUnit.MINUTES); }
@Test(expected = ExecutionException.class) public void testPublishFailureRetries_nonRetryableFailsImmediately() throws Exception { Publisher publisher = getTestPublisherBuilder() .setExecutorProvider(SINGLE_THREAD_EXECUTOR) .setRetrySettings( Publisher.Builder.DEFAULT_RETRY_SETTINGS .toBuilder() .setTotalTimeout(Duration.ofSeconds(10)) .build()) .setBatchingSettings( Publisher.Builder.DEFAULT_BATCHING_SETTINGS .toBuilder() .setElementCountThreshold(1L) .setDelayThreshold(Duration.ofSeconds(5)) .build()) .build(); // To demonstrate that reaching duration will trigger publish testPublisherServiceImpl.addPublishError(new StatusException(Status.INVALID_ARGUMENT)); ApiFuture<String> publishFuture1 = sendTestMessage(publisher, "A"); try { publishFuture1.get(); } finally { assertTrue(testPublisherServiceImpl.getCapturedRequests().size() >= 1); publisher.shutdown(); publisher.awaitTermination(1, TimeUnit.MINUTES); } }
.toBuilder() .setInitialRpcTimeout(Publisher.Builder.MIN_RPC_TIMEOUT) .build()); builder.setRetrySettings( Publisher.Builder.DEFAULT_RETRY_SETTINGS .toBuilder() .setInitialRpcTimeout(Publisher.Builder.MIN_RPC_TIMEOUT.minusMillis(1)) .build()); .toBuilder() .setTotalTimeout(Publisher.Builder.MIN_TOTAL_TIMEOUT) .build()); builder.setRetrySettings( Publisher.Builder.DEFAULT_RETRY_SETTINGS .toBuilder() .setTotalTimeout(Publisher.Builder.MIN_TOTAL_TIMEOUT.minusMillis(1)) .build());
.bulkMutationsSettings() .getRetrySettings() .toBuilder() .setMaxAttempts(MAX_ATTEMPTS) .setInitialRetryDelay(Duration.ofMillis(10))
@Test(expected = ApiException.class) public void retryMaxAttemptsExceeded() { ImmutableSet<StatusCode.Code> retryable = ImmutableSet.of(Code.UNAVAILABLE); Mockito.when(callInt.futureCall((Integer) Mockito.any(), (ApiCallContext) Mockito.any())) .thenReturn(RetryingTest.<Integer>immediateFailedFuture(HTTP_SERVICE_UNAVAILABLE_EXCEPTION)) .thenReturn(RetryingTest.<Integer>immediateFailedFuture(HTTP_SERVICE_UNAVAILABLE_EXCEPTION)) .thenReturn(ApiFutures.<Integer>immediateFuture(2)); RetrySettings retrySettings = FAST_RETRY_SETTINGS.toBuilder().setMaxAttempts(2).build(); UnaryCallSettings<Integer, Integer> callSettings = createSettings(retryable, retrySettings); UnaryCallable<Integer, Integer> callable = HttpJsonCallableFactory.createUnaryCallable(callInt, callSettings, clientContext); callable.call(1); }
@Test public void retryWithinMaxAttempts() { ImmutableSet<StatusCode.Code> retryable = ImmutableSet.of(Code.UNAVAILABLE); Mockito.when(callInt.futureCall((Integer) Mockito.any(), (ApiCallContext) Mockito.any())) .thenReturn(RetryingTest.<Integer>immediateFailedFuture(HTTP_SERVICE_UNAVAILABLE_EXCEPTION)) .thenReturn(RetryingTest.<Integer>immediateFailedFuture(HTTP_SERVICE_UNAVAILABLE_EXCEPTION)) .thenReturn(ApiFutures.<Integer>immediateFuture(2)); RetrySettings retrySettings = FAST_RETRY_SETTINGS.toBuilder().setMaxAttempts(3).build(); UnaryCallSettings<Integer, Integer> callSettings = createSettings(retryable, retrySettings); UnaryCallable<Integer, Integer> callable = HttpJsonCallableFactory.createUnaryCallable(callInt, callSettings, clientContext); callable.call(1); Truth.assertThat(callable.call(1)).isEqualTo(2); }
@Test(expected = ApiException.class) public void retryMaxAttemptsExceeded() { Throwable throwable = new UnavailableException(null, FakeStatusCode.of(StatusCode.Code.UNAVAILABLE), true); Mockito.when(callInt.futureCall((Integer) Mockito.any(), (ApiCallContext) Mockito.any())) .thenReturn(RetryingTest.<Integer>immediateFailedFuture(throwable)) .thenReturn(RetryingTest.<Integer>immediateFailedFuture(throwable)) .thenReturn(ApiFutures.<Integer>immediateFuture(2)); RetrySettings retrySettings = FAST_RETRY_SETTINGS.toBuilder().setMaxAttempts(2).build(); UnaryCallSettings<Integer, Integer> callSettings = createSettings(retrySettings); UnaryCallable<Integer, Integer> callable = FakeCallableFactory.createUnaryCallable(callInt, callSettings, clientContext); callable.call(1); }
@Test public void retryWithinMaxAttempts() { Throwable throwable = new UnavailableException(null, FakeStatusCode.of(StatusCode.Code.UNAVAILABLE), true); Mockito.when(callInt.futureCall((Integer) Mockito.any(), (ApiCallContext) Mockito.any())) .thenReturn(RetryingTest.<Integer>immediateFailedFuture(throwable)) .thenReturn(RetryingTest.<Integer>immediateFailedFuture(throwable)) .thenReturn(ApiFutures.<Integer>immediateFuture(2)); RetrySettings retrySettings = FAST_RETRY_SETTINGS.toBuilder().setMaxAttempts(3).build(); UnaryCallSettings<Integer, Integer> callSettings = createSettings(retrySettings); UnaryCallable<Integer, Integer> callable = FakeCallableFactory.createUnaryCallable(callInt, callSettings, clientContext); callable.call(1); Truth.assertThat(callable.call(1)).isEqualTo(2); }
@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(expected = ApiException.class) public void retryTotalTimeoutExceeded() { Throwable throwable = new UnavailableException(null, FakeStatusCode.of(StatusCode.Code.UNAVAILABLE), true); Mockito.when(callInt.futureCall((Integer) Mockito.any(), (ApiCallContext) Mockito.any())) .thenReturn(RetryingTest.<Integer>immediateFailedFuture(throwable)) .thenReturn(ApiFutures.<Integer>immediateFuture(2)); RetrySettings retrySettings = FAST_RETRY_SETTINGS .toBuilder() .setInitialRetryDelay(Duration.ofMillis(Integer.MAX_VALUE)) .setMaxRetryDelay(Duration.ofMillis(Integer.MAX_VALUE)) .build(); UnaryCallSettings<Integer, Integer> callSettings = createSettings(retrySettings); UnaryCallable<Integer, Integer> callable = FakeCallableFactory.createUnaryCallable(callInt, callSettings, clientContext); callable.call(1); }
@Test(expected = ApiException.class) public void retryTotalTimeoutExceeded() { ImmutableSet<StatusCode.Code> retryable = ImmutableSet.of(Code.UNAVAILABLE); HttpResponseException httpResponseException = new HttpResponseException.Builder( HttpStatusCodes.STATUS_CODE_SERVICE_UNAVAILABLE, "server unavailable", new HttpHeaders()) .build(); ApiException apiException = ApiExceptionFactory.createException( "foobar", httpResponseException, HttpJsonStatusCode.of(Code.FAILED_PRECONDITION), false); Mockito.when(callInt.futureCall((Integer) Mockito.any(), (ApiCallContext) Mockito.any())) .thenReturn(RetryingTest.<Integer>immediateFailedFuture(apiException)) .thenReturn(ApiFutures.<Integer>immediateFuture(2)); RetrySettings retrySettings = FAST_RETRY_SETTINGS .toBuilder() .setInitialRetryDelay(Duration.ofMillis(Integer.MAX_VALUE)) .setMaxRetryDelay(Duration.ofMillis(Integer.MAX_VALUE)) .build(); UnaryCallSettings<Integer, Integer> callSettings = createSettings(retryable, retrySettings); UnaryCallable<Integer, Integer> callable = HttpJsonCallableFactory.createUnaryCallable(callInt, callSettings, clientContext); callable.call(1); }
@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); }
@Before public void setUp() throws IOException { initialChannel = mock(FakeChannel.class); pollTransportChannel = mock(TransportChannel.class); TransportChannelProvider operationsChannelProvider = mock(TransportChannelProvider.class); when(operationsChannelProvider.getTransportChannel()).thenReturn(pollTransportChannel); clock = new FakeApiClock(0L); executor = RecordingScheduler.create(clock); pollingAlgorithm = OperationTimedPollAlgorithm.create(FAST_RECHECKING_SETTINGS, clock); UnaryCallSettings<Integer, OperationSnapshot> initialCallSettings = UnaryCallSettings.<Integer, OperationSnapshot>newUnaryCallSettingsBuilder() .setRetrySettings(FAST_RETRY_SETTINGS.toBuilder().setMaxAttempts(1).build()) .build(); callSettings = OperationCallSettings.<Integer, Color, Currency>newBuilder() .setInitialCallSettings(initialCallSettings) .setResponseTransformer(new ResponseTransformer()) .setMetadataTransformer(new MetadataTransformer()) .setPollingAlgorithm(pollingAlgorithm) .build(); initialContext = getClientContext(initialChannel, executor); }
OperationTimedPollAlgorithm.create( FAST_RECHECKING_SETTINGS .toBuilder() .setTotalTimeout(Duration.ofMillis(iterationsCount)) .build(),
@Test public void testFutureCallPollCancelOnLongTimeoutExceeded() throws Exception { final int iterationsCount = 1000; String opName = "testFutureCallPollCancelOnLongTimeoutExceeded"; OperationSnapshot initialOperation = getOperation(opName, null, null, null, false); OperationSnapshot[] pollOperations = new OperationSnapshot[iterationsCount]; for (int i = 0; i < iterationsCount; i++) { pollOperations[i] = getOperation(opName, null, null, null, false); } UnaryCallable<Integer, OperationSnapshot> initialCallable = mockGetOpSnapshotCallable(StatusCode.Code.OK, initialOperation); LongRunningClient longRunningClient = mockGetOperation(StatusCode.Code.OK, pollOperations); pollingAlgorithm = OperationTimedPollAlgorithm.create( FAST_RECHECKING_SETTINGS.toBuilder().setTotalTimeout(Duration.ofMillis(1000L)).build(), clock); callSettings = callSettings.toBuilder().setPollingAlgorithm(pollingAlgorithm).build(); OperationCallable<Integer, Color, Currency> callable = FakeCallableFactory.createOperationCallable( initialCallable, callSettings, initialContext, longRunningClient); OperationFuture<Color, Currency> future = callable.futureCall(2, FakeCallContext.createDefault()); assertFutureCancelMetaCancel(future); assertThat(executor.getIterationsCount()).isEqualTo(iterationsCount); }