Skip to content
This repository has been archived by the owner on Sep 26, 2023. It is now read-only.

Reconcile RetrySettings & Clock #235

Merged
merged 17 commits into from
Mar 20, 2017
Merged

Conversation

vam-google
Copy link
Contributor

Reconcile RetrySettings in GAX with RetryParams in google-cloud-java
googleapis/google-cloud-java#1574
Reconcile NanoClock in GAX with Clock in google-cloud-java
googleapis/google-cloud-java#1575

Reconcile RetrySettings in GAX with RetryParams in google-cloud-java
googleapis/google-cloud-java#1574
Reconcile NanoClock in GAX with Clock in google-cloud-java
googleapis/google-cloud-java#1575
@codecov-io
Copy link

codecov-io commented Mar 11, 2017

Codecov Report

Merging #235 into master will increase coverage by 0.76%.
The diff coverage is 88.42%.

@@             Coverage Diff              @@
##             master     #235      +/-   ##
============================================
+ Coverage     70.27%   71.03%   +0.76%     
- Complexity      478      523      +45     
============================================
  Files            68       75       +7     
  Lines          2476     2593     +117     
  Branches        253      267      +14     
============================================
+ Hits           1740     1842     +102     
- Misses          639      648       +9     
- Partials         97      103       +6
Impacted Files Coverage Δ Complexity Δ
...gax/core/internal/ApiFutureToListenableFuture.java 60% <ø> (ø) 3 <0> (ø) ⬇️
...le/api/gax/retrying/ScheduledRetryingExecutor.java 100% <100%> (ø) 3 <3> (?)
.../google/api/gax/retrying/TimedAttemptSettings.java 100% <100%> (ø) 7 <7> (?)
...le/api/gax/retrying/ExponentialRetryAlgorithm.java 100% <100%> (ø) 8 <8> (?)
...in/java/com/google/api/gax/grpc/UnaryCallable.java 92% <100%> (+2%) 17 <1> (ø) ⬇️
...va/com/google/api/gax/retrying/RetryAlgorithm.java 100% <100%> (ø) 7 <7> (?)
...c/main/java/com/google/api/gax/core/NanoClock.java 66.66% <60%> (ø) 4 <3> (?)
...in/java/com/google/api/gax/core/RetrySettings.java 41.02% <60%> (-0.65%) 3 <2> (ø)
...oogle/api/gax/retrying/DirectRetryingExecutor.java 81.25% <81.25%> (ø) 4 <4> (?)
...om/google/api/gax/retrying/RetryingFutureImpl.java 82.25% <82.25%> (ø) 13 <13> (?)
... and 9 more

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 8cbfcc3...db34591. Read the comment docs.

Copy link
Member

@garrettjonesgoogle garrettjonesgoogle left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I started this review on Friday, so apologies if I call out any issues that have already been resolved with PR updates.

@@ -0,0 +1,61 @@
/*
* Copyright 2016, Google Inc. All rights reserved.

This comment was marked as spam.

This comment was marked as spam.

This comment was marked as spam.

import java.io.Serializable;
import java.util.concurrent.TimeUnit;

public final class SystemClock implements NanoClock, Serializable {

This comment was marked as spam.

This comment was marked as spam.

*
* @param <ResponseT> response type
*/
public abstract class AbstractRetryHandler<ResponseT> implements RetryHandler<ResponseT> {

This comment was marked as spam.

This comment was marked as spam.

}

/**
* Ensures that the retry logic hasn't exceeded neither maximum number of retries nor the total

This comment was marked as spam.

/**
* Execution attempt settings. Defines attempt-specific properties of a retry process.
*/
public class RetryAttemptSettings {

This comment was marked as spam.

This comment was marked as spam.

This comment was marked as spam.

clock.setCurrentNanoTime(clock.nanoTime() + TimeUnit.NANOSECONDS.convert(delay, unit));
return executor.schedule(runnable, 0, TimeUnit.NANOSECONDS);
}
static RecordingScheduler get(final FakeNanoClock clock) {

This comment was marked as spam.

This comment was marked as spam.

@Override
public List<Runnable> shutdownNow() {
return executor.shutdownNow();
private abstract static class LatchCountDownScheduler implements ScheduledExecutorService {

This comment was marked as spam.

This comment was marked as spam.

@@ -92,6 +95,13 @@
public abstract Duration getMaxRetryDelay();

/**
* MaxAttempts defines the maximum number of attempts to perform. If number of attempts reaches

This comment was marked as spam.

@@ -92,6 +95,13 @@
public abstract Duration getMaxRetryDelay();

/**
* MaxAttempts defines the maximum number of attempts to perform. If number of attempts reaches
* this limit the logic will give up retrying even if the total retry time is still lower than

This comment was marked as spam.

private static boolean canRetry(Throwable throwable) {
if (!(throwable instanceof ApiException)) {
return false;
private static class GrpcRetryCallable<RequestT, ResponseT> implements Callable<ResponseT> {

This comment was marked as spam.

@@ -92,6 +95,13 @@
public abstract Duration getMaxRetryDelay();

/**
* MaxAttempts defines the maximum number of attempts to perform. If number of attempts reaches
* this limit the logic will give up retrying even if the total retry time is still lower than
* TotalTimeout.

This comment was marked as spam.

This comment was marked as spam.

return resultFuture;
GrpcRetryCallable<RequestT, ResponseT> retryCallable =
new GrpcRetryCallable<>(callable, request, context);
GrpcRetryHandler<ResponseT> retryHelper = new GrpcRetryHandler<>(clock, scheduler);

This comment was marked as spam.

This comment was marked as spam.

GrpcRetryCallable<RequestT, ResponseT> retryCallable =
new GrpcRetryCallable<>(callable, request, context);
GrpcRetryHandler<ResponseT> retryHelper = new GrpcRetryHandler<>(clock, scheduler);
RetryFuture<ResponseT> rv = retryHelper.createFirstAttempt(retryCallable, retryParams);

This comment was marked as spam.

This comment was marked as spam.

@Override
public RetryAttemptSettings createNextAttemptSettings(
Throwable e, RetryAttemptSettings prevSettings) {
if (((ApiException) e).getStatusCode() == Code.DEADLINE_EXCEEDED) {

This comment was marked as spam.

This comment was marked as spam.

*
* @param <ResponseT> response type
*/
public abstract class AbstractRetryHandler<ResponseT> implements RetryHandler<ResponseT> {

This comment was marked as spam.

This comment was marked as spam.

This comment was marked as spam.

@vam-google
Copy link
Contributor Author

Addressed review comments, PTAL.

callbackFutureCallback.attemptFuture.cancel(mayInterruptIfRunning);
boolean rv = callbackFutureCallback.attemptFuture.cancel(mayInterruptIfRunning);
super.cancel(mayInterruptIfRunning);
return rv;

This comment was marked as spam.

This comment was marked as spam.

return totalTimeSpentNanos <= totalTimeoutNanos
&& (globalSettings.getMaxAttempts() <= 0
|| nextAttemptSettings.getAttemptCount() < globalSettings.getMaxAttempts());
}

This comment was marked as spam.

if (Duration.ZERO.compareTo(attemptSettings.getRandomizedRetryDelay()) < 0) {
Thread.sleep(attemptSettings.getRandomizedRetryDelay().getMillis());
}
return Futures.immediateFuture(callable.call());

This comment was marked as spam.

/**
* Execution attempt settings. Defines attempt-specific properties of a retry process.
*/
public class RetryAttemptSettings {

This comment was marked as spam.

* @param attemptSettings current attempt settings
* @return the {@link Future}, representing the scheduled execution
*/
Future<ResponseT> executeAttempt(

This comment was marked as spam.

private final ScheduledExecutorService executor;
private final List<Duration> sleepDurations = new ArrayList<>();
private final FakeNanoClock clock;
abstract class RecordingScheduler implements ScheduledExecutorService {

This comment was marked as spam.

* this limit the logic will give up retrying even if the total retry time is still lower than
* TotalTimeout.
*/
public abstract Builder setMaxAttempts(int maxAttempts);

This comment was marked as spam.

This comment was marked as spam.

… 2) time-specific and 3) exception-specific retry logics.

2. Removed abstract classes
3. Renamed NanoClock to ApiClock, as it has System.currentTimeMillis() implementation, and NanoClock name is misleading now.
@vam-google
Copy link
Contributor Author

PTAL

Addressed the review comments, plus some other smaller changes:

  1. Split RetryHandler on 3 different components: 1) scheduling logic, 2) time-specific and 3) exception-specific retry logics.
  2. Removed abstract classes.
  3. Renamed NanoClock to ApiClock, as it has System.currentTimeMillis() implementation, and NanoClock name is misleading now.

import java.util.concurrent.TimeUnit;

/** Default implementation of the ApiClock interface, using call to System.nanoTime(). */
public final class NanoClock implements ApiClock, Serializable {

This comment was marked as spam.

This comment was marked as spam.

This comment was marked as spam.

This comment was marked as spam.

* Implementation of the {@link ApiClock} interface, which uses {@link System#currentTimeMillis()}
* as time source.
*/
public final class SystemClock implements ApiClock, Serializable {

This comment was marked as spam.

This comment was marked as spam.

}
if (attemptFuture != null) {
attemptFutureCallback = new AttemptFutureCallback(attemptFuture);
Futures.addCallback((ListenableFuture) attemptFuture, attemptFutureCallback);

This comment was marked as spam.

This comment was marked as spam.

This comment was marked as spam.

This comment was marked as spam.

This comment was marked as spam.

activeFuture = callFuture;
}
}
return null;

This comment was marked as spam.

This comment was marked as spam.

* Returns {@code true} if another attempt should be made, or {@code false} otherwise.
*
* @param prevThrowable exception thrown by the previous attempt
* @return {@code true} if another attempt should be made, or {@code false} otherwise

This comment was marked as spam.

This comment was marked as spam.

This comment was marked as spam.

}

/**
* Creates a first attempt {@link TimedAttemptSettings}. By default the first attempt is

This comment was marked as spam.

This comment was marked as spam.

Throwable prevThrowable, TimedAttemptSettings prevSettings) {
TimedAttemptSettings newSettings =
exceptionAlgorithm.createNextAttempt(prevThrowable, prevSettings);
if (prevSettings.equals(newSettings)) {

This comment was marked as spam.

This comment was marked as spam.

This comment was marked as spam.

This comment was marked as spam.

*
* <ol>
* <li>Creating first attempt {@link RetryingFuture}, which acts as a facade, hiding from client
* code the actual scheduled retry attempts execution.

This comment was marked as spam.

This comment was marked as spam.

*
* @param retryingFuture the future previously returned by {@link #createFuture(Callable)}
*/
void submit(RetryingFuture<ResponseT> retryingFuture);

This comment was marked as spam.

Copy link
Contributor

@shinfan shinfan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good overall. Just a few more comments.

@@ -189,6 +206,13 @@ public Builder toBuilder() {
public abstract double getRetryDelayMultiplier();

/**
* MaxAttempts defines the maximum number of attempts to perform. If number of attempts reaches

This comment was marked as spam.

CallContext oldCtx, Duration rpcTimeout) {
CallOptions oldOpt = oldCtx.getCallOptions();
CallOptions newOpt = oldOpt.withDeadlineAfter(rpcTimeout.getMillis(), TimeUnit.MILLISECONDS);
CallContext newCtx = oldCtx.withCallOptions(newOpt);

This comment was marked as spam.

This comment was marked as spam.

/**
* Timed attempt execution settings. Defines time-specific properties of a retry attempt.
*/
public class TimedAttemptSettings {

This comment was marked as spam.

This comment was marked as spam.

This comment was marked as spam.

}

/**
* Submits an attempt for execution in a different thread.

This comment was marked as spam.

This comment was marked as spam.

new GrpcRetryCallable<>(callable, request, context);

RetryingFuture<ResponseT> retryingFuture = scheduler.createFuture(retryCallable);
retryCallable.setExternalFuture(retryingFuture);

This comment was marked as spam.

This comment was marked as spam.

@vam-google
Copy link
Contributor Author

Adressed PR comments, PTAL.

@vam-google
Copy link
Contributor Author

PTAL

@garrettjonesgoogle
Copy link
Member

Offline agreements:

  1. Rename SystemClock to CurrentMillisClock
  2. Have ExceptionAlgorithm.createNextAttempt return null if it is not overriding the settings

LGTM after these are done - Shin should probably also approve.

…e next attempt settings. renamed SystemClock to CurrentMillisClock.
@vam-google
Copy link
Contributor Author

PTAL

Copy link
Contributor

@shinfan shinfan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just one more comment


/**
* The retry executor which uses {@link ScheduledExecutorService} to schedule an attempt tasks.
* Unless a direct executor service is used, this handler will schedule attempts for an execution in

This comment was marked as spam.

This comment was marked as spam.

@vam-google
Copy link
Contributor Author

Done

@shinfan
Copy link
Contributor

shinfan commented Mar 17, 2017

LGTM

@vam-google vam-google merged commit dfb7021 into googleapis:master Mar 20, 2017
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants