Skip to content

Commit a598db8

Browse files
igorbernstein2Raibaz
authored andcommitted
Add RetryingContext (googleapis#590)
1 parent 4c95e02 commit a598db8

16 files changed

Lines changed: 247 additions & 63 deletions

gax/src/main/java/com/google/api/gax/retrying/BasicRetryingFuture.java

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,15 +57,20 @@ class BasicRetryingFuture<ResponseT> extends AbstractFuture<ResponseT>
5757
private final Callable<ResponseT> callable;
5858

5959
private final RetryAlgorithm<ResponseT> retryAlgorithm;
60+
private final RetryingContext retryingContext;
6061

6162
private volatile TimedAttemptSettings attemptSettings;
6263

6364
private volatile ApiFuture<ResponseT> latestCompletedAttemptResult;
6465
private volatile ApiFuture<ResponseT> attemptResult;
6566

66-
BasicRetryingFuture(Callable<ResponseT> callable, RetryAlgorithm<ResponseT> retryAlgorithm) {
67+
BasicRetryingFuture(
68+
Callable<ResponseT> callable,
69+
RetryAlgorithm<ResponseT> retryAlgorithm,
70+
RetryingContext context) {
6771
this.callable = checkNotNull(callable);
6872
this.retryAlgorithm = checkNotNull(retryAlgorithm);
73+
this.retryingContext = checkNotNull(context);
6974

7075
this.attemptSettings = retryAlgorithm.createFirstAttempt();
7176

gax/src/main/java/com/google/api/gax/retrying/CallbackChainRetryingFuture.java

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -52,14 +52,15 @@
5252
* <p>This class is thread-safe.
5353
*/
5454
class CallbackChainRetryingFuture<ResponseT> extends BasicRetryingFuture<ResponseT> {
55-
private final RetryingExecutor<ResponseT> retryingExecutor;
55+
private final ScheduledRetryingExecutor<ResponseT> retryingExecutor;
5656
private volatile AttemptCompletionListener attemptFutureCompletionListener;
5757

5858
CallbackChainRetryingFuture(
5959
Callable<ResponseT> callable,
6060
RetryAlgorithm<ResponseT> retryAlgorithm,
61-
RetryingExecutor<ResponseT> retryingExecutor) {
62-
super(callable, retryAlgorithm);
61+
ScheduledRetryingExecutor<ResponseT> retryingExecutor,
62+
RetryingContext context) {
63+
super(callable, retryAlgorithm, context);
6364
this.retryingExecutor = checkNotNull(retryingExecutor);
6465
}
6566

gax/src/main/java/com/google/api/gax/retrying/DirectRetryingExecutor.java

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333

3434
import com.google.api.core.ApiFuture;
3535
import com.google.api.core.ApiFutures;
36+
import com.google.api.core.BetaApi;
3637
import java.io.InterruptedIOException;
3738
import java.nio.channels.ClosedByInterruptException;
3839
import java.util.concurrent.Callable;
@@ -46,7 +47,7 @@
4647
*
4748
* @param <ResponseT> response type
4849
*/
49-
public class DirectRetryingExecutor<ResponseT> implements RetryingExecutor<ResponseT> {
50+
public class DirectRetryingExecutor<ResponseT> implements RetryingExecutorWithContext<ResponseT> {
5051

5152
private final RetryAlgorithm<ResponseT> retryAlgorithm;
5253

@@ -70,15 +71,30 @@ public DirectRetryingExecutor(RetryAlgorithm<ResponseT> retryAlgorithm) {
7071
*/
7172
@Override
7273
public RetryingFuture<ResponseT> createFuture(Callable<ResponseT> callable) {
73-
return new BasicRetryingFuture<>(callable, retryAlgorithm);
74+
return createFuture(callable, NoopRetryingContext.create());
75+
}
76+
77+
/**
78+
* Creates a {@link RetryingFuture}, which is a facade, returned to the client code to wait for
79+
* any retriable operation to complete. The future is bounded to {@code this} executor instance.
80+
*
81+
* @param callable the actual callable, which should be executed in a retriable context
82+
* @return retrying future facade
83+
*/
84+
@BetaApi("The surface for passing per operation state is not yet stable")
85+
@Override
86+
public RetryingFuture<ResponseT> createFuture(
87+
Callable<ResponseT> callable, RetryingContext context) {
88+
return new BasicRetryingFuture<>(callable, retryAlgorithm, context);
7489
}
7590

7691
/**
7792
* Submits an attempt for execution in the current thread, causing the current thread to sleep for
7893
* the specified by the {@link RetryingFuture#getAttemptSettings()} amount of time. As result,
7994
* this method completes execution only after the specified {@code retryingFuture} completes.
8095
*
81-
* @param retryingFuture the future previously returned by {@link #createFuture(Callable)}
96+
* @param retryingFuture the future previously returned by {@link #createFuture(Callable,
97+
* RetryingContext)}
8298
* @return returns completed {@code retryingFuture}
8399
*/
84100
@Override
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
/*
2+
* Copyright 2018 Google LLC
3+
*
4+
* Redistribution and use in source and binary forms, with or without
5+
* modification, are permitted provided that the following conditions are
6+
* met:
7+
*
8+
* * Redistributions of source code must retain the above copyright
9+
* notice, this list of conditions and the following disclaimer.
10+
* * Redistributions in binary form must reproduce the above
11+
* copyright notice, this list of conditions and the following disclaimer
12+
* in the documentation and/or other materials provided with the
13+
* distribution.
14+
* * Neither the name of Google LLC nor the names of its
15+
* contributors may be used to endorse or promote products derived from
16+
* this software without specific prior written permission.
17+
*
18+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19+
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20+
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21+
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22+
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23+
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24+
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25+
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26+
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27+
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28+
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29+
*/
30+
package com.google.api.gax.retrying;
31+
32+
// TODO(igorbernstein2): Remove this class once RetryingExecutor#createFuture(Callable) is
33+
// deprecated and removed.
34+
/**
35+
* Backwards compatibility class to aid in transition to adding operation state to {@link
36+
* RetryingFuture} implementations.
37+
*/
38+
class NoopRetryingContext implements RetryingContext {
39+
public static RetryingContext create() {
40+
return new NoopRetryingContext();
41+
}
42+
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
/*
2+
* Copyright 2018 Google LLC
3+
*
4+
* Redistribution and use in source and binary forms, with or without
5+
* modification, are permitted provided that the following conditions are
6+
* met:
7+
*
8+
* * Redistributions of source code must retain the above copyright
9+
* notice, this list of conditions and the following disclaimer.
10+
* * Redistributions in binary form must reproduce the above
11+
* copyright notice, this list of conditions and the following disclaimer
12+
* in the documentation and/or other materials provided with the
13+
* distribution.
14+
* * Neither the name of Google LLC nor the names of its
15+
* contributors may be used to endorse or promote products derived from
16+
* this software without specific prior written permission.
17+
*
18+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19+
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20+
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21+
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22+
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23+
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24+
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25+
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26+
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27+
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28+
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29+
*/
30+
package com.google.api.gax.retrying;
31+
32+
import com.google.api.core.BetaApi;
33+
34+
/**
35+
* Context for a retryable operation.
36+
*
37+
* <p>It provides state to individual {@link RetryingFuture}s via the {@link RetryingExecutor}.
38+
*/
39+
@BetaApi("The surface for passing per operation state is not yet stable")
40+
public interface RetryingContext {}
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
/*
2+
* Copyright 2018 Google LLC
3+
*
4+
* Redistribution and use in source and binary forms, with or without
5+
* modification, are permitted provided that the following conditions are
6+
* met:
7+
*
8+
* * Redistributions of source code must retain the above copyright
9+
* notice, this list of conditions and the following disclaimer.
10+
* * Redistributions in binary form must reproduce the above
11+
* copyright notice, this list of conditions and the following disclaimer
12+
* in the documentation and/or other materials provided with the
13+
* distribution.
14+
* * Neither the name of Google LLC nor the names of its
15+
* contributors may be used to endorse or promote products derived from
16+
* this software without specific prior written permission.
17+
*
18+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19+
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20+
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21+
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22+
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23+
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24+
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25+
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26+
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27+
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28+
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29+
*/
30+
package com.google.api.gax.retrying;
31+
32+
import com.google.api.core.BetaApi;
33+
import com.google.api.core.InternalExtensionOnly;
34+
import java.util.concurrent.Callable;
35+
import javax.annotation.Nonnull;
36+
37+
/**
38+
* A {@link RetryingExecutor} that accepts a per-operation context.
39+
*
40+
* @see RetryingExecutor
41+
*/
42+
// TODO(igorbernstein2): Consider replacing this with a default implementation in RetryingExecutor
43+
// once support for java 7 is dropped
44+
@BetaApi("The surface for per invocation state is unstable and will probably change in the future")
45+
@InternalExtensionOnly
46+
public interface RetryingExecutorWithContext<ResponseT> extends RetryingExecutor<ResponseT> {
47+
RetryingFuture<ResponseT> createFuture(
48+
@Nonnull Callable<ResponseT> callable, @Nonnull RetryingContext context);
49+
}

gax/src/main/java/com/google/api/gax/retrying/ScheduledRetryingExecutor.java

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131

3232
import com.google.api.core.ApiFuture;
3333
import com.google.api.core.ApiFutures;
34+
import com.google.api.core.BetaApi;
3435
import com.google.api.core.ListenableFutureToApiFuture;
3536
import com.google.common.util.concurrent.ListenableFuture;
3637
import com.google.common.util.concurrent.ListeningScheduledExecutorService;
@@ -53,7 +54,8 @@
5354
*
5455
* @param <ResponseT> response type
5556
*/
56-
public class ScheduledRetryingExecutor<ResponseT> implements RetryingExecutor<ResponseT> {
57+
public class ScheduledRetryingExecutor<ResponseT>
58+
implements RetryingExecutorWithContext<ResponseT> {
5759

5860
private final RetryAlgorithm<ResponseT> retryAlgorithm;
5961
private final ListeningScheduledExecutorService scheduler;
@@ -81,13 +83,30 @@ public ScheduledRetryingExecutor(
8183
*/
8284
@Override
8385
public RetryingFuture<ResponseT> createFuture(Callable<ResponseT> callable) {
84-
return new CallbackChainRetryingFuture<>(callable, retryAlgorithm, this);
86+
return createFuture(callable, NoopRetryingContext.create());
87+
}
88+
89+
/**
90+
* Creates a {@link RetryingFuture}, which is a facade, returned to the client code to wait for
91+
* any retriable operation to complete. The returned future is bounded to {@code this} executor
92+
* instance.
93+
*
94+
* @param callable the actual callable, which should be executed in a retriable context
95+
* @param context the context for this operation
96+
* @return retrying future facade
97+
*/
98+
@BetaApi("The surface for passing per operation state is not yet stable")
99+
@Override
100+
public RetryingFuture<ResponseT> createFuture(
101+
Callable<ResponseT> callable, RetryingContext context) {
102+
return new CallbackChainRetryingFuture<>(callable, retryAlgorithm, this, context);
85103
}
86104

87105
/**
88106
* Submits an attempt for execution in a different thread.
89107
*
90-
* @param retryingFuture the future previously returned by {@link #createFuture(Callable)}
108+
* @param retryingFuture the future previously returned by {@link #createFuture(Callable,
109+
* RetryingContext)}
91110
* @return submitted attempt future
92111
*/
93112
@Override

gax/src/main/java/com/google/api/gax/rpc/ApiCallContext.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131

3232
import com.google.api.core.BetaApi;
3333
import com.google.api.core.InternalExtensionOnly;
34+
import com.google.api.gax.retrying.RetryingContext;
3435
import com.google.auth.Credentials;
3536
import java.util.List;
3637
import java.util.Map;
@@ -48,7 +49,7 @@
4849
* <p>This is transport specific and each transport has an implementation with its own options.
4950
*/
5051
@InternalExtensionOnly
51-
public interface ApiCallContext {
52+
public interface ApiCallContext extends RetryingContext {
5253

5354
/** Returns a new ApiCallContext with the given credentials set. */
5455
ApiCallContext withCredentials(Credentials credentials);

gax/src/main/java/com/google/api/gax/rpc/Callables.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,6 @@
3535
import com.google.api.gax.longrunning.OperationSnapshot;
3636
import com.google.api.gax.retrying.ExponentialRetryAlgorithm;
3737
import com.google.api.gax.retrying.RetryAlgorithm;
38-
import com.google.api.gax.retrying.RetryingExecutor;
3938
import com.google.api.gax.retrying.ScheduledRetryingExecutor;
4039
import com.google.api.gax.retrying.StreamingRetryAlgorithm;
4140

@@ -64,7 +63,7 @@ public static <RequestT, ResponseT> UnaryCallable<RequestT, ResponseT> retrying(
6463
new ApiResultRetryAlgorithm<ResponseT>(),
6564
new ExponentialRetryAlgorithm(
6665
callSettings.getRetrySettings(), clientContext.getClock()));
67-
RetryingExecutor<ResponseT> retryingExecutor =
66+
ScheduledRetryingExecutor<ResponseT> retryingExecutor =
6867
new ScheduledRetryingExecutor<>(retryAlgorithm, clientContext.getExecutor());
6968
return new RetryingCallable<>(
7069
clientContext.getDefaultCallContext(), innerCallable, retryingExecutor);

gax/src/main/java/com/google/api/gax/rpc/OperationCallableImpl.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@
3636
import com.google.api.gax.longrunning.OperationFuture;
3737
import com.google.api.gax.longrunning.OperationFutureImpl;
3838
import com.google.api.gax.longrunning.OperationSnapshot;
39-
import com.google.api.gax.retrying.RetryingExecutor;
39+
import com.google.api.gax.retrying.RetryingExecutorWithContext;
4040
import com.google.api.gax.retrying.RetryingFuture;
4141

4242
/**
@@ -50,14 +50,14 @@ class OperationCallableImpl<RequestT, ResponseT, MetadataT>
5050
extends OperationCallable<RequestT, ResponseT, MetadataT> {
5151

5252
private final UnaryCallable<RequestT, OperationSnapshot> initialCallable;
53-
private final RetryingExecutor<OperationSnapshot> executor;
53+
private final RetryingExecutorWithContext<OperationSnapshot> executor;
5454
private final LongRunningClient longRunningClient;
5555
private final ApiFunction<OperationSnapshot, ResponseT> responseTransformer;
5656
private final ApiFunction<OperationSnapshot, MetadataT> metadataTransformer;
5757

5858
OperationCallableImpl(
5959
UnaryCallable<RequestT, OperationSnapshot> initialCallable,
60-
RetryingExecutor<OperationSnapshot> executor,
60+
RetryingExecutorWithContext<OperationSnapshot> executor,
6161
LongRunningClient longRunningClient,
6262
OperationCallSettings<RequestT, ResponseT, MetadataT> operationCallSettings) {
6363
this.initialCallable = checkNotNull(initialCallable);

0 commit comments

Comments
 (0)