/** Initializes a new stream to the backend with backoff. */ private void initStream() { firestoreExecutor.schedule( new Runnable() { @Override public void run() { if (!isActive.get()) { return; } synchronized (Watch.this) { if (!isActive.get()) { return; } Preconditions.checkState(stream == null); current = false; nextAttempt = backoff.createNextAttempt(nextAttempt); stream = firestore.streamRequest(Watch.this, firestore.getClient().listenCallable()); ListenRequest.Builder request = ListenRequest.newBuilder(); request.setDatabase(firestore.getDatabaseName()); request.setAddTarget(target); if (resumeToken != null) { request.getAddTargetBuilder().setResumeToken(resumeToken); } stream.onNext(request.build()); } } }, nextAttempt.getRandomizedRetryDelay().toMillis(), TimeUnit.MILLISECONDS); }
/** Initializes a new stream to the backend with backoff. */ private void initStream() { firestoreExecutor.schedule( new Runnable() { @Override public void run() { if (!isActive.get()) { return; } synchronized (Watch.this) { if (!isActive.get()) { return; } Preconditions.checkState(stream == null); current = false; nextAttempt = backoff.createNextAttempt(nextAttempt); stream = firestore.streamRequest(Watch.this, firestore.getClient().listenCallable()); ListenRequest.Builder request = ListenRequest.newBuilder(); request.setDatabase(firestore.getDatabaseName()); request.setAddTarget(target); if (resumeToken != null) { request.getAddTargetBuilder().setResumeToken(resumeToken); } stream.onNext(request.build()); } } }, nextAttempt.getRandomizedRetryDelay().toMillis(), TimeUnit.MILLISECONDS); }
/** * Submits an attempt for execution in the current thread, causing the current thread to sleep for * the specified by the {@link RetryingFuture#getAttemptSettings()} amount of time. As result, * this method completes execution only after the specified {@code retryingFuture} completes. * * @param retryingFuture the future previously returned by {@link #createFuture(Callable, * RetryingContext)} * @return returns completed {@code retryingFuture} */ @Override public ApiFuture<ResponseT> submit(RetryingFuture<ResponseT> retryingFuture) { while (!retryingFuture.isDone()) { try { sleep(retryingFuture.getAttemptSettings().getRandomizedRetryDelay()); ResponseT response = retryingFuture.getCallable().call(); retryingFuture.setAttemptFuture(ApiFutures.immediateFuture(response)); } catch (InterruptedException | InterruptedIOException | ClosedByInterruptException e) { Thread.currentThread().interrupt(); retryingFuture.setAttemptFuture(ApiFutures.<ResponseT>immediateFailedFuture(e)); } catch (Exception e) { retryingFuture.setAttemptFuture(ApiFutures.<ResponseT>immediateFailedFuture(e)); } } return retryingFuture; }
/** * Submits an attempt for execution in the current thread, causing the current thread to sleep for * the specified by the {@link RetryingFuture#getAttemptSettings()} amount of time. As result, * this method completes execution only after the specified {@code retryingFuture} completes. * * @param retryingFuture the future previously returned by {@link #createFuture(Callable, * RetryingContext)} * @return returns completed {@code retryingFuture} */ @Override public ApiFuture<ResponseT> submit(RetryingFuture<ResponseT> retryingFuture) { while (!retryingFuture.isDone()) { try { sleep(retryingFuture.getAttemptSettings().getRandomizedRetryDelay()); ResponseT response = retryingFuture.getCallable().call(); retryingFuture.setAttemptFuture(ApiFutures.immediateFuture(response)); } catch (InterruptedException | InterruptedIOException | ClosedByInterruptException e) { Thread.currentThread().interrupt(); retryingFuture.setAttemptFuture(ApiFutures.<ResponseT>immediateFailedFuture(e)); } catch (Exception e) { retryingFuture.setAttemptFuture(ApiFutures.<ResponseT>immediateFailedFuture(e)); } } return retryingFuture; }
/** * Submits an attempt for execution in a different thread. * * @param retryingFuture the future previously returned by {@link #createFuture(Callable, * RetryingContext)} * @return submitted attempt future */ @Override public ApiFuture<ResponseT> submit(RetryingFuture<ResponseT> retryingFuture) { try { ListenableFuture<ResponseT> attemptFuture = scheduler.schedule( retryingFuture.getCallable(), retryingFuture.getAttemptSettings().getRandomizedRetryDelay().toMillis(), TimeUnit.MILLISECONDS); return new ListenableFutureToApiFuture<>(attemptFuture); } catch (RejectedExecutionException e) { return ApiFutures.immediateFailedFuture(e); } } }
/** * Submits an attempt for execution in a different thread. * * @param retryingFuture the future previously returned by {@link #createFuture(Callable, * RetryingContext)} * @return submitted attempt future */ @Override public ApiFuture<ResponseT> submit(RetryingFuture<ResponseT> retryingFuture) { try { ListenableFuture<ResponseT> attemptFuture = scheduler.schedule( retryingFuture.getCallable(), retryingFuture.getAttemptSettings().getRandomizedRetryDelay().toMillis(), TimeUnit.MILLISECONDS); return new ListenableFutureToApiFuture<>(attemptFuture); } catch (RejectedExecutionException e) { return ApiFutures.immediateFailedFuture(e); } } }
/** * Returns {@code true} if another attempt should be made, or {@code false} otherwise. * * @param nextAttemptSettings attempt settings, which will be used for the next attempt, if * accepted * @return {@code true} if {@code nextAttemptSettings} does not exceed either maxAttempts limit or * totalTimeout limit, or {@code false} otherwise */ @Override public boolean shouldRetry(TimedAttemptSettings nextAttemptSettings) { RetrySettings globalSettings = nextAttemptSettings.getGlobalSettings(); long totalTimeSpentNanos = clock.nanoTime() - nextAttemptSettings.getFirstAttemptStartTimeNanos() + nextAttemptSettings.getRandomizedRetryDelay().toNanos(); return totalTimeSpentNanos <= globalSettings.getTotalTimeout().toNanos() && (globalSettings.getMaxAttempts() <= 0 || nextAttemptSettings.getAttemptCount() < globalSettings.getMaxAttempts()); }
/** * Returns {@code true} if another attempt should be made, or {@code false} otherwise. * * @param nextAttemptSettings attempt settings, which will be used for the next attempt, if * accepted * @return {@code true} if {@code nextAttemptSettings} does not exceed either maxAttempts limit or * totalTimeout limit, or {@code false} otherwise */ @Override public boolean shouldRetry(TimedAttemptSettings nextAttemptSettings) { RetrySettings globalSettings = nextAttemptSettings.getGlobalSettings(); long totalTimeSpentNanos = clock.nanoTime() - nextAttemptSettings.getFirstAttemptStartTimeNanos() + nextAttemptSettings.getRandomizedRetryDelay().toNanos(); return totalTimeSpentNanos <= globalSettings.getTotalTimeout().toNanos() && (globalSettings.getMaxAttempts() <= 0 || nextAttemptSettings.getAttemptCount() < globalSettings.getMaxAttempts()); }
@Test public void testCreateFirstAttempt() { TimedAttemptSettings attempt = algorithm.createFirstAttempt(); // Checking only the most core values, to not make this test too implementation specific. assertEquals(0, attempt.getAttemptCount()); assertEquals(0, attempt.getOverallAttemptCount()); assertEquals(Duration.ZERO, attempt.getRetryDelay()); assertEquals(Duration.ZERO, attempt.getRandomizedRetryDelay()); assertEquals(Duration.ofMillis(1L), attempt.getRpcTimeout()); assertEquals(Duration.ZERO, attempt.getRetryDelay()); }
@Test public void testCreateNextAttempt() { TimedAttemptSettings firstAttempt = algorithm.createFirstAttempt(); TimedAttemptSettings secondAttempt = algorithm.createNextAttempt(firstAttempt); // Checking only the most core values, to not make this test too implementation specific. assertEquals(1, secondAttempt.getAttemptCount()); assertEquals(1, secondAttempt.getOverallAttemptCount()); assertEquals(Duration.ofMillis(1L), secondAttempt.getRetryDelay()); assertEquals(Duration.ofMillis(1L), secondAttempt.getRandomizedRetryDelay()); assertEquals(Duration.ofMillis(2L), secondAttempt.getRpcTimeout()); TimedAttemptSettings thirdAttempt = algorithm.createNextAttempt(secondAttempt); assertEquals(2, thirdAttempt.getAttemptCount()); assertEquals(Duration.ofMillis(2L), thirdAttempt.getRetryDelay()); assertEquals(Duration.ofMillis(2L), thirdAttempt.getRandomizedRetryDelay()); assertEquals(Duration.ofMillis(4L), thirdAttempt.getRpcTimeout()); }
boolean shouldRetry = retryAlgorithm.shouldRetry(throwable, response, nextAttemptSettings); if (shouldRetry) { tracer.attemptFailed(throwable, nextAttemptSettings.getRandomizedRetryDelay()); attemptSettings = nextAttemptSettings; setAttemptResult(throwable, response, true);
boolean shouldRetry = retryAlgorithm.shouldRetry(throwable, response, nextAttemptSettings); if (shouldRetry) { tracer.attemptFailed(throwable, nextAttemptSettings.getRandomizedRetryDelay()); attemptSettings = nextAttemptSettings; setAttemptResult(throwable, response, true);