AckHandler(String ackId, int outstandingBytes, Instant totalExpiration) { this.ackId = ackId; this.outstandingBytes = outstandingBytes; this.receivedTimeMillis = clock.millisTime(); this.totalExpiration = totalExpiration; }
/** * 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()); }
private Instant now() { return Instant.ofEpochMilli(clock.millisTime()); } }
protected Long getNextBackoff() { if (currentBackoff == null) { // Historically, the client waited for "total timeout" after the first failure. For now, // that behavior is preserved, even though that's not the ideal. // // TODO: Think through retries, and create policy that works with the mental model most // users would have of relating to retries. That would likely involve updating some // default settings in addition to changing the algorithm. currentBackoff = exponentialRetryAlgorithm.createFirstAttempt(); } currentBackoff = exponentialRetryAlgorithm.createNextAttempt(currentBackoff); if (!exponentialRetryAlgorithm.shouldRetry(currentBackoff)) { // TODO: consider creating a subclass of exponentialRetryAlgorithm to encapsulate this logic long timeLeftNs = currentBackoff.getGlobalSettings().getTotalTimeout().toNanos() - (clock.nanoTime() - currentBackoff.getFirstAttemptStartTimeNanos()); long timeLeftMs = TimeUnit.NANOSECONDS.toMillis(timeLeftNs); if (timeLeftMs > currentBackoff.getGlobalSettings().getInitialRetryDelay().toMillis()) { // The backoff algorithm doesn't always wait until the timeout is achieved. Wait // one final time so that retries hit return timeLeftMs; } else { // Finish for real. return null; } } else { return currentBackoff.getRetryDelay().toMillis(); } }
@Override public void onSuccess(AckReply reply) { LinkedBlockingQueue<String> destination; switch (reply) { case ACK: destination = pendingAcks; // Record the latency rounded to the next closest integer. ackLatencyDistribution.record( Ints.saturatedCast( (long) Math.ceil((clock.millisTime() - receivedTimeMillis) / 1000D))); break; case NACK: destination = pendingNacks; break; default: throw new IllegalArgumentException(String.format("AckReply: %s not supported", reply)); } destination.add(ackId); forget(); } }
/** * Creates a first attempt {@link TimedAttemptSettings}. The first attempt is configured to be * executed immediately. * * @return first attempt settings */ @Override public TimedAttemptSettings createFirstAttempt() { return TimedAttemptSettings.newBuilder() .setGlobalSettings(globalSettings) .setRetryDelay(Duration.ZERO) .setRpcTimeout(globalSettings.getInitialRpcTimeout()) .setRandomizedRetryDelay(Duration.ZERO) .setAttemptCount(0) .setOverallAttemptCount(0) .setFirstAttemptStartTimeNanos(clock.nanoTime()) .build(); }
getOptions().getClock().millisTime() + unit.toMillis(duration), TimeUnit.MILLISECONDS);
/** * Creates a first attempt {@link TimedAttemptSettings}. The first attempt is configured to be * executed immediately. * * @return first attempt settings */ @Override public TimedAttemptSettings createFirstAttempt() { return TimedAttemptSettings.newBuilder() .setGlobalSettings(globalSettings) .setRetryDelay(Duration.ZERO) .setRpcTimeout(globalSettings.getInitialRpcTimeout()) .setRandomizedRetryDelay(Duration.ZERO) .setAttemptCount(0) .setOverallAttemptCount(0) .setFirstAttemptStartTimeNanos(clock.nanoTime()) .build(); }
@Override public void onResponseImpl(ResponseT response) { synchronized (lock) { state = State.DELIVERING; } outerResponseObserver.onResponse(response); synchronized (lock) { pendingCount--; lastActivityAt = clock.millisTime(); if (autoAutoFlowControl || pendingCount > 0) { state = State.WAITING; } else { state = State.IDLE; } } }
@Override public void onResponseImpl(ResponseT response) { synchronized (lock) { state = State.DELIVERING; } outerResponseObserver.onResponse(response); synchronized (lock) { pendingCount--; lastActivityAt = clock.millisTime(); if (autoAutoFlowControl || pendingCount > 0) { state = State.WAITING; } else { state = State.IDLE; } } }
private void onRequest(int count) { Preconditions.checkArgument(count > 0, "count must be > 0"); Preconditions.checkState(!autoAutoFlowControl, "Auto flow control is enabled"); // Only reset the request water mark if there are no outstanding requests. synchronized (lock) { if (state == State.IDLE) { state = State.WAITING; lastActivityAt = clock.millisTime(); } // Increment the request count without overflow int maxIncrement = Integer.MAX_VALUE - pendingCount; count = Math.min(maxIncrement, count); pendingCount += count; } innerController.request(count); }
private void onRequest(int count) { Preconditions.checkArgument(count > 0, "count must be > 0"); Preconditions.checkState(!autoAutoFlowControl, "Auto flow control is enabled"); // Only reset the request water mark if there are no outstanding requests. synchronized (lock) { if (state == State.IDLE) { state = State.WAITING; lastActivityAt = clock.millisTime(); } // Increment the request count without overflow int maxIncrement = Integer.MAX_VALUE - pendingCount; count = Math.min(maxIncrement, count); pendingCount += count; } innerController.request(count); }
getOptions().getClock().millisTime() + unit.toMillis(duration), TimeUnit.MILLISECONDS);
private void checkForTimeout(long initialMillis) throws TimeoutException { if (photosLibrarySettings.uploadMediaItemSettings().getRetrySettings().getTotalTimeout() != UNLIMITED_TIMEOUT) { long duration = clientContext.getClock().millisTime() - initialMillis; if (duration > photosLibrarySettings .uploadMediaItemSettings() .getRetrySettings() .getTotalTimeout() .get(MILLIS)) { throw new TimeoutException(ExceptionStrings.UPLOAD_TIMED_OUT); } } }
long initialMillis = clientContext.getClock().millisTime();
long waitTime = clock.millisTime() - lastActivityAt;
long waitTime = clock.millisTime() - lastActivityAt;