-
Notifications
You must be signed in to change notification settings - Fork 107
Conversation
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 Report
@@ 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
Continue to review full report at Codecov.
|
There was a problem hiding this 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.
Sorry, something went wrong.
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
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.
Sorry, something went wrong.
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
* | ||
* @param <ResponseT> response type | ||
*/ | ||
public abstract class AbstractRetryHandler<ResponseT> implements RetryHandler<ResponseT> { |
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
} | ||
|
||
/** | ||
* Ensures that the retry logic hasn't exceeded neither maximum number of retries nor the total |
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
/** | ||
* 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.
Sorry, something went wrong.
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
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.
Sorry, something went wrong.
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
@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.
Sorry, something went wrong.
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
@@ -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.
This comment was marked as spam.
Sorry, something went wrong.
@@ -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.
This comment was marked as spam.
Sorry, something went wrong.
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.
This comment was marked as spam.
Sorry, something went wrong.
@@ -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.
Sorry, something went wrong.
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
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.
Sorry, something went wrong.
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
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.
Sorry, something went wrong.
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
@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.
Sorry, something went wrong.
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
* | ||
* @param <ResponseT> response type | ||
*/ | ||
public abstract class AbstractRetryHandler<ResponseT> implements RetryHandler<ResponseT> { |
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
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.
Sorry, something went wrong.
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
return totalTimeSpentNanos <= totalTimeoutNanos | ||
&& (globalSettings.getMaxAttempts() <= 0 | ||
|| nextAttemptSettings.getAttemptCount() < globalSettings.getMaxAttempts()); | ||
} |
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
if (Duration.ZERO.compareTo(attemptSettings.getRandomizedRetryDelay()) < 0) { | ||
Thread.sleep(attemptSettings.getRandomizedRetryDelay().getMillis()); | ||
} | ||
return Futures.immediateFuture(callable.call()); |
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
/** | ||
* 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.
Sorry, something went wrong.
* @param attemptSettings current attempt settings | ||
* @return the {@link Future}, representing the scheduled execution | ||
*/ | ||
Future<ResponseT> executeAttempt( |
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
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 comment was marked as spam.
Sorry, something went wrong.
* 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.
Sorry, something went wrong.
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
… 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.
PTAL Addressed the review comments, plus some other smaller changes:
|
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.
Sorry, something went wrong.
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
* 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.
Sorry, something went wrong.
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
} | ||
if (attemptFuture != null) { | ||
attemptFutureCallback = new AttemptFutureCallback(attemptFuture); | ||
Futures.addCallback((ListenableFuture) attemptFuture, attemptFutureCallback); |
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
activeFuture = callFuture; | ||
} | ||
} | ||
return null; |
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
* 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.
Sorry, something went wrong.
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
} | ||
|
||
/** | ||
* Creates a first attempt {@link TimedAttemptSettings}. By default the first attempt is |
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
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.
Sorry, something went wrong.
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
* | ||
* <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.
Sorry, something went wrong.
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
* | ||
* @param retryingFuture the future previously returned by {@link #createFuture(Callable)} | ||
*/ | ||
void submit(RetryingFuture<ResponseT> retryingFuture); |
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
There was a problem hiding this 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.
This comment was marked as spam.
Sorry, something went wrong.
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.
Sorry, something went wrong.
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
/** | ||
* 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.
Sorry, something went wrong.
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
} | ||
|
||
/** | ||
* Submits an attempt for execution in a different thread. |
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
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.
Sorry, something went wrong.
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
Adressed PR comments, PTAL. |
PTAL |
Offline agreements:
LGTM after these are done - Shin should probably also approve. |
…e next attempt settings. renamed SystemClock to CurrentMillisClock.
…tryAlgorithm, which now returns null)
PTAL |
There was a problem hiding this 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.
Sorry, something went wrong.
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
Done |
LGTM |
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