Skip to content

Commit

Permalink
Merge pull request googleapis#3 from pongad/retryparams
Browse files Browse the repository at this point in the history
Split RetryParams
  • Loading branch information
garrettjonesgoogle committed Feb 5, 2016
2 parents 95bd977 + 25a3a66 commit ac8a53f
Show file tree
Hide file tree
Showing 4 changed files with 152 additions and 66 deletions.
79 changes: 79 additions & 0 deletions src/main/java/io/gapi/gax/grpc/BackoffParams.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
/*
* Copyright 2016, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

package io.gapi.gax.grpc;

import com.google.auto.value.AutoValue;

/**
* {@code BackoffParams} encapsulates parameters for exponential backoff.
*/
@AutoValue
public abstract class BackoffParams {
public abstract long getInitialDelayMillis();

public abstract double getDelayMultiplier();

public abstract long getMaxDelayMillis();

public static Builder newBuilder() {
return new AutoValue_BackoffParams.Builder();
}

public Builder toBuilder() {
return new AutoValue_BackoffParams.Builder(this);
}

@AutoValue.Builder
public abstract static class Builder {
public abstract Builder setInitialDelayMillis(long initialDelayMillis);

public abstract Builder setDelayMultiplier(double delayMultiplier);

public abstract Builder setMaxDelayMillis(long maxDelayMillis);

abstract BackoffParams autoBuild();

public BackoffParams build() {
BackoffParams backoff = autoBuild();
if (backoff.getInitialDelayMillis() < 0) {
throw new IllegalStateException("initial delay must not be negative");
}
if (backoff.getDelayMultiplier() < 1.0) {
throw new IllegalStateException("delay multiplier must be at least 1");
}
if (backoff.getMaxDelayMillis() < backoff.getInitialDelayMillis()) {
throw new IllegalStateException("max delay must not be smaller than initial delay");
}
return backoff;
}
}
}
101 changes: 43 additions & 58 deletions src/main/java/io/gapi/gax/grpc/RetryParams.java
Original file line number Diff line number Diff line change
Expand Up @@ -31,81 +31,66 @@

package io.gapi.gax.grpc;

import com.google.auto.value.AutoValue;

/**
* {@code RetryParams} encapsulates a retry strategy used by
* {@link io.gapi.gax.grpc.ApiCallable#retrying(RetryParams)}.
*/
public final class RetryParams {
public static final long DEFAULT_INITIAL_RETRY_DELAY = 10L;
public static final long DEFAULT_MAX_RETRY_DELAY = 1000L;
public static final double DEFAULT_RETRY_DELAY_MULT = 1.2;
public static final long DEFAULT_INITIAL_RPC_TIMEOUT = 3000L;
public static final long DEFAULT_MAX_RPC_TIMEOUT = 10000L;
public static final double DEFAULT_RPC_TIMEOUT_MULT = 1.2;
public static final long DEFAULT_TOTAL_TIMEOUT = 30000L;
@AutoValue
public abstract class RetryParams {
// TODO(pongad): deprecate DEFAULT in favor of code-generation-time config
private static final BackoffParams DEFAULT_RETRY_BACKOFF =
BackoffParams.newBuilder()
.setInitialDelayMillis(10L)
.setDelayMultiplier(1.2)
.setMaxDelayMillis(1000L)
.build();

public static final RetryParams DEFAULT =
new RetryParams(
DEFAULT_INITIAL_RETRY_DELAY,
DEFAULT_MAX_RETRY_DELAY,
DEFAULT_RETRY_DELAY_MULT,
DEFAULT_INITIAL_RPC_TIMEOUT,
DEFAULT_MAX_RPC_TIMEOUT,
DEFAULT_RPC_TIMEOUT_MULT,
DEFAULT_TOTAL_TIMEOUT);
private static final BackoffParams DEFAULT_TIMEOUT_BACKOFF =
BackoffParams.newBuilder()
.setInitialDelayMillis(3000L)
.setDelayMultiplier(1.2)
.setMaxDelayMillis(10000L)
.build();

private final long initialRetryDelay;
private final long maxRetryDelay;
private final double retryDelayMult;
static final RetryParams DEFAULT =
RetryParams.newBuilder()
.setRetryBackoff(DEFAULT_RETRY_BACKOFF)
.setTimeoutBackoff(DEFAULT_TIMEOUT_BACKOFF)
.setTotalTimeout(30000L)
.build();

private final long initialRpcTimeout;
private final long maxRpcTimeout;
private final double rpcTimeoutMult;
public abstract BackoffParams getRetryBackoff();

private final long totalTimeout;
public abstract BackoffParams getTimeoutBackoff();

public RetryParams(
long initialRetryDelay,
long maxRetryDelay,
double retryDelayMult,
long initialRpcTimeout,
long maxRpcTimeout,
double rpcTimeoutMult,
long totalTimeout) {
this.initialRetryDelay = initialRetryDelay;
this.maxRetryDelay = maxRetryDelay;
this.retryDelayMult = retryDelayMult;
this.initialRpcTimeout = initialRpcTimeout;
this.maxRpcTimeout = maxRpcTimeout;
this.rpcTimeoutMult = rpcTimeoutMult;
this.totalTimeout = totalTimeout;
}
public abstract long getTotalTimeout();

public long getInitialRetryDelay() {
return initialRetryDelay;
public static Builder newBuilder() {
return new AutoValue_RetryParams.Builder();
}

public long getMaxRetryDelay() {
return maxRetryDelay;
public Builder toBuilder() {
return new AutoValue_RetryParams.Builder(this);
}

public double getRetryDelayMult() {
return retryDelayMult;
}
@AutoValue.Builder
public abstract static class Builder {
public abstract Builder setRetryBackoff(BackoffParams retryBackoff);

public long getInitialRpcTimeout() {
return initialRpcTimeout;
}
public abstract Builder setTimeoutBackoff(BackoffParams timeoutBackoff);

public long getMaxRpcTimeout() {
return maxRpcTimeout;
}
public abstract Builder setTotalTimeout(long totalTimeout);

public double getRpcTimeoutMult() {
return rpcTimeoutMult;
}
abstract RetryParams autoBuild();

public long getTotalTimeout() {
return totalTimeout;
public RetryParams build() {
RetryParams params = autoBuild();
if (params.getTotalTimeout() < 0) {
throw new IllegalStateException("total timeout must not be negative");
}
return params;
}
}
}
18 changes: 11 additions & 7 deletions src/main/java/io/gapi/gax/grpc/RetryingCallable.java
Original file line number Diff line number Diff line change
Expand Up @@ -76,8 +76,8 @@ public ListenableFuture<ResponseT> futureCall(CallContext<RequestT> context) {
new Retryer(
context,
result,
retryParams.getInitialRetryDelay(),
retryParams.getInitialRpcTimeout(),
retryParams.getRetryBackoff().getInitialDelayMillis(),
retryParams.getTimeoutBackoff().getInitialDelayMillis(),
null);
retryer.run();
return result;
Expand Down Expand Up @@ -135,11 +135,15 @@ public void onFailure(Throwable throwable) {
result.setException(throwable);
return;
}
long newRetryDelay = (long) (retryDelay * retryParams.getRetryDelayMult());
newRetryDelay = Math.min(newRetryDelay, retryParams.getMaxRetryDelay());

long newRpcTimeout = (long) (rpcTimeout * retryParams.getRpcTimeoutMult());
newRpcTimeout = Math.min(newRpcTimeout, retryParams.getMaxRpcTimeout());
long newRetryDelay =
(long) (retryDelay * retryParams.getRetryBackoff().getDelayMultiplier());
newRetryDelay =
Math.min(newRetryDelay, retryParams.getRetryBackoff().getMaxDelayMillis());

long newRpcTimeout =
(long) (rpcTimeout * retryParams.getTimeoutBackoff().getDelayMultiplier());
newRpcTimeout =
Math.min(newRpcTimeout, retryParams.getTimeoutBackoff().getMaxDelayMillis());

long randomRetryDelay = ThreadLocalRandom.current().nextLong(retryDelay);

Expand Down
20 changes: 19 additions & 1 deletion src/test/java/io/gapi/gax/grpc/ApiCallableTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -55,20 +55,38 @@
@RunWith(JUnit4.class)
public class ApiCallableTest {
FutureCallable<Integer, Integer> callInt = Mockito.mock(FutureCallable.class);
RetryParams testRetryParams = new RetryParams(1, 1, 1, 1, 1, 1, 100);

private static final RetryParams testRetryParams;

static {
BackoffParams backoff =
BackoffParams.newBuilder()
.setInitialDelayMillis(1)
.setDelayMultiplier(1)
.setMaxDelayMillis(1)
.build();
testRetryParams =
RetryParams.newBuilder()
.setRetryBackoff(backoff)
.setTimeoutBackoff(backoff)
.setTotalTimeout(10L)
.build();
}

@Rule public ExpectedException thrown = ExpectedException.none();

// Bind
// ====
private static class StashCallable<ReqT, RespT> implements FutureCallable<ReqT, RespT> {
CallContext<ReqT> context;

@Override
public ListenableFuture<RespT> futureCall(CallContext<ReqT> context) {
this.context = context;
return null;
}
}

@Test
public void bind() {
Channel channel = Mockito.mock(Channel.class);
Expand Down

0 comments on commit ac8a53f

Please # to comment.