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

Commit 7f7aa25

Browse files
authored
feat: support retry settings and retryable codes in call context (#1238)
* feat: support retry settings and retryable codes in call context Allows applications to supply retry settings and retryabe codes for individual RPCs through ApiCallContext. Fixes #1197 * chore: fix formatting and license headers * feat: use context retry settings for streaming calls * fix: process review comments * fix: missed one Thread.sleep * fix: fix style * fix: address review comments * refactor: remove ContextAwareResultRetryAlgorithm * refactor: remove ContextAwareTimedRetryAlgorithm * fix: make package-private + add ignored * revert: revert to always using global settings for jittered * test: add tests for NoopRetryingContext * chore: cleanup 'this' usage * refactor: merge context aware classes with base classes * chore: cleanup and remove unnecessary methods * test: add safety margin as the retry settings are now jittered * docs: add javadoc * chore: address review comments * fix: address review comments * fix: add tests + fix potential NPE * fix: remove unused method + add tests * test: add additional test calls * fix: deprecation
1 parent 86d5c72 commit 7f7aa25

30 files changed

+2093
-254
lines changed

‎gax-grpc/src/main/java/com/google/api/gax/grpc/GrpcCallContext.java

Lines changed: 137 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -30,14 +30,17 @@
3030
package com.google.api.gax.grpc;
3131

3232
import com.google.api.core.BetaApi;
33+
import com.google.api.gax.retrying.RetrySettings;
3334
import com.google.api.gax.rpc.ApiCallContext;
35+
import com.google.api.gax.rpc.StatusCode;
3436
import com.google.api.gax.rpc.TransportChannel;
3537
import com.google.api.gax.rpc.internal.Headers;
3638
import com.google.api.gax.tracing.ApiTracer;
3739
import com.google.api.gax.tracing.NoopApiTracer;
3840
import com.google.auth.Credentials;
3941
import com.google.common.base.Preconditions;
4042
import com.google.common.collect.ImmutableMap;
43+
import com.google.common.collect.ImmutableSet;
4144
import io.grpc.CallCredentials;
4245
import io.grpc.CallOptions;
4346
import io.grpc.CallOptions.Key;
@@ -48,6 +51,7 @@
4851
import java.util.List;
4952
import java.util.Map;
5053
import java.util.Objects;
54+
import java.util.Set;
5155
import javax.annotation.Nonnull;
5256
import javax.annotation.Nullable;
5357
import org.threeten.bp.Duration;
@@ -70,18 +74,36 @@ public final class GrpcCallContext implements ApiCallContext {
7074
@Nullable private final Duration streamWaitTimeout;
7175
@Nullable private final Duration streamIdleTimeout;
7276
@Nullable private final Integer channelAffinity;
77+
@Nullable private final RetrySettings retrySettings;
78+
@Nullable private final ImmutableSet<StatusCode.Code> retryableCodes;
7379
private final ImmutableMap<String, List<String>> extraHeaders;
7480

7581
/** Returns an empty instance with a null channel and default {@link CallOptions}. */
7682
public static GrpcCallContext createDefault() {
7783
return new GrpcCallContext(
78-
null, CallOptions.DEFAULT, null, null, null, null, ImmutableMap.<String, List<String>>of());
84+
null,
85+
CallOptions.DEFAULT,
86+
null,
87+
null,
88+
null,
89+
null,
90+
ImmutableMap.<String, List<String>>of(),
91+
null,
92+
null);
7993
}
8094

8195
/** Returns an instance with the given channel and {@link CallOptions}. */
8296
public static GrpcCallContext of(Channel channel, CallOptions callOptions) {
8397
return new GrpcCallContext(
84-
channel, callOptions, null, null, null, null, ImmutableMap.<String, List<String>>of());
98+
channel,
99+
callOptions,
100+
null,
101+
null,
102+
null,
103+
null,
104+
ImmutableMap.<String, List<String>>of(),
105+
null,
106+
null);
85107
}
86108

87109
private GrpcCallContext(
@@ -91,14 +113,18 @@ private GrpcCallContext(
91113
@Nullable Duration streamWaitTimeout,
92114
@Nullable Duration streamIdleTimeout,
93115
@Nullable Integer channelAffinity,
94-
ImmutableMap<String, List<String>> extraHeaders) {
116+
ImmutableMap<String, List<String>> extraHeaders,
117+
@Nullable RetrySettings retrySettings,
118+
@Nullable Set<StatusCode.Code> retryableCodes) {
95119
this.channel = channel;
96120
this.callOptions = Preconditions.checkNotNull(callOptions);
97121
this.timeout = timeout;
98122
this.streamWaitTimeout = streamWaitTimeout;
99123
this.streamIdleTimeout = streamIdleTimeout;
100124
this.channelAffinity = channelAffinity;
101125
this.extraHeaders = Preconditions.checkNotNull(extraHeaders);
126+
this.retrySettings = retrySettings;
127+
this.retryableCodes = retryableCodes == null ? null : ImmutableSet.copyOf(retryableCodes);
102128
}
103129

104130
/**
@@ -160,7 +186,9 @@ public GrpcCallContext withTimeout(@Nullable Duration timeout) {
160186
this.streamWaitTimeout,
161187
this.streamIdleTimeout,
162188
this.channelAffinity,
163-
this.extraHeaders);
189+
this.extraHeaders,
190+
this.retrySettings,
191+
this.retryableCodes);
164192
}
165193

166194
@Nullable
@@ -177,13 +205,15 @@ public GrpcCallContext withStreamWaitTimeout(@Nullable Duration streamWaitTimeou
177205
}
178206

179207
return new GrpcCallContext(
180-
channel,
181-
callOptions,
182-
timeout,
208+
this.channel,
209+
this.callOptions,
210+
this.timeout,
183211
streamWaitTimeout,
184-
streamIdleTimeout,
185-
channelAffinity,
186-
extraHeaders);
212+
this.streamIdleTimeout,
213+
this.channelAffinity,
214+
this.extraHeaders,
215+
this.retrySettings,
216+
this.retryableCodes);
187217
}
188218

189219
@Override
@@ -194,25 +224,29 @@ public GrpcCallContext withStreamIdleTimeout(@Nullable Duration streamIdleTimeou
194224
}
195225

196226
return new GrpcCallContext(
197-
channel,
198-
callOptions,
199-
timeout,
200-
streamWaitTimeout,
227+
this.channel,
228+
this.callOptions,
229+
this.timeout,
230+
this.streamWaitTimeout,
201231
streamIdleTimeout,
202-
channelAffinity,
203-
extraHeaders);
232+
this.channelAffinity,
233+
this.extraHeaders,
234+
this.retrySettings,
235+
this.retryableCodes);
204236
}
205237

206238
@BetaApi("The surface for channel affinity is not stable yet and may change in the future.")
207239
public GrpcCallContext withChannelAffinity(@Nullable Integer affinity) {
208240
return new GrpcCallContext(
209-
channel,
210-
callOptions,
211-
timeout,
212-
streamWaitTimeout,
213-
streamIdleTimeout,
241+
this.channel,
242+
this.callOptions,
243+
this.timeout,
244+
this.streamWaitTimeout,
245+
this.streamIdleTimeout,
214246
affinity,
215-
extraHeaders);
247+
this.extraHeaders,
248+
this.retrySettings,
249+
this.retryableCodes);
216250
}
217251

218252
@BetaApi("The surface for extra headers is not stable yet and may change in the future.")
@@ -222,13 +256,53 @@ public GrpcCallContext withExtraHeaders(Map<String, List<String>> extraHeaders)
222256
ImmutableMap<String, List<String>> newExtraHeaders =
223257
Headers.mergeHeaders(this.extraHeaders, extraHeaders);
224258
return new GrpcCallContext(
225-
channel,
226-
callOptions,
227-
timeout,
228-
streamWaitTimeout,
229-
streamIdleTimeout,
230-
channelAffinity,
231-
newExtraHeaders);
259+
this.channel,
260+
this.callOptions,
261+
this.timeout,
262+
this.streamWaitTimeout,
263+
this.streamIdleTimeout,
264+
this.channelAffinity,
265+
newExtraHeaders,
266+
this.retrySettings,
267+
this.retryableCodes);
268+
}
269+
270+
@Override
271+
public RetrySettings getRetrySettings() {
272+
return this.retrySettings;
273+
}
274+
275+
@Override
276+
public GrpcCallContext withRetrySettings(RetrySettings retrySettings) {
277+
return new GrpcCallContext(
278+
this.channel,
279+
this.callOptions,
280+
this.timeout,
281+
this.streamWaitTimeout,
282+
this.streamIdleTimeout,
283+
this.channelAffinity,
284+
this.extraHeaders,
285+
retrySettings,
286+
this.retryableCodes);
287+
}
288+
289+
@Override
290+
public Set<StatusCode.Code> getRetryableCodes() {
291+
return this.retryableCodes;
292+
}
293+
294+
@Override
295+
public GrpcCallContext withRetryableCodes(Set<StatusCode.Code> retryableCodes) {
296+
return new GrpcCallContext(
297+
this.channel,
298+
this.callOptions,
299+
this.timeout,
300+
this.streamWaitTimeout,
301+
this.streamIdleTimeout,
302+
this.channelAffinity,
303+
this.extraHeaders,
304+
this.retrySettings,
305+
retryableCodes);
232306
}
233307

234308
@Override
@@ -283,8 +357,18 @@ public ApiCallContext merge(ApiCallContext inputCallContext) {
283357
newChannelAffinity = this.channelAffinity;
284358
}
285359

360+
RetrySettings newRetrySettings = grpcCallContext.retrySettings;
361+
if (newRetrySettings == null) {
362+
newRetrySettings = this.retrySettings;
363+
}
364+
365+
Set<StatusCode.Code> newRetryableCodes = grpcCallContext.retryableCodes;
366+
if (newRetryableCodes == null) {
367+
newRetryableCodes = this.retryableCodes;
368+
}
369+
286370
ImmutableMap<String, List<String>> newExtraHeaders =
287-
Headers.mergeHeaders(extraHeaders, grpcCallContext.extraHeaders);
371+
Headers.mergeHeaders(this.extraHeaders, grpcCallContext.extraHeaders);
288372

289373
CallOptions newCallOptions =
290374
grpcCallContext
@@ -303,7 +387,9 @@ public ApiCallContext merge(ApiCallContext inputCallContext) {
303387
newStreamWaitTimeout,
304388
newStreamIdleTimeout,
305389
newChannelAffinity,
306-
newExtraHeaders);
390+
newExtraHeaders,
391+
newRetrySettings,
392+
newRetryableCodes);
307393
}
308394

309395
/** The {@link Channel} set on this context. */
@@ -357,23 +443,27 @@ public GrpcCallContext withChannel(Channel newChannel) {
357443
return new GrpcCallContext(
358444
newChannel,
359445
this.callOptions,
360-
timeout,
446+
this.timeout,
361447
this.streamWaitTimeout,
362448
this.streamIdleTimeout,
363449
this.channelAffinity,
364-
this.extraHeaders);
450+
this.extraHeaders,
451+
this.retrySettings,
452+
this.retryableCodes);
365453
}
366454

367455
/** Returns a new instance with the call options set to the given call options. */
368456
public GrpcCallContext withCallOptions(CallOptions newCallOptions) {
369457
return new GrpcCallContext(
370458
this.channel,
371459
newCallOptions,
372-
timeout,
460+
this.timeout,
373461
this.streamWaitTimeout,
374462
this.streamIdleTimeout,
375463
this.channelAffinity,
376-
this.extraHeaders);
464+
this.extraHeaders,
465+
this.retrySettings,
466+
this.retryableCodes);
377467
}
378468

379469
public GrpcCallContext withRequestParamsDynamicHeaderOption(String requestParams) {
@@ -410,7 +500,9 @@ public int hashCode() {
410500
streamWaitTimeout,
411501
streamIdleTimeout,
412502
channelAffinity,
413-
extraHeaders);
503+
extraHeaders,
504+
retrySettings,
505+
retryableCodes);
414506
}
415507

416508
@Override
@@ -423,13 +515,15 @@ public boolean equals(Object o) {
423515
}
424516

425517
GrpcCallContext that = (GrpcCallContext) o;
426-
return Objects.equals(channel, that.channel)
427-
&& Objects.equals(callOptions, that.callOptions)
428-
&& Objects.equals(timeout, that.timeout)
429-
&& Objects.equals(streamWaitTimeout, that.streamWaitTimeout)
430-
&& Objects.equals(streamIdleTimeout, that.streamIdleTimeout)
431-
&& Objects.equals(channelAffinity, that.channelAffinity)
432-
&& Objects.equals(extraHeaders, that.extraHeaders);
518+
return Objects.equals(this.channel, that.channel)
519+
&& Objects.equals(this.callOptions, that.callOptions)
520+
&& Objects.equals(this.timeout, that.timeout)
521+
&& Objects.equals(this.streamWaitTimeout, that.streamWaitTimeout)
522+
&& Objects.equals(this.streamIdleTimeout, that.streamIdleTimeout)
523+
&& Objects.equals(this.channelAffinity, that.channelAffinity)
524+
&& Objects.equals(this.extraHeaders, that.extraHeaders)
525+
&& Objects.equals(this.retrySettings, that.retrySettings)
526+
&& Objects.equals(this.retryableCodes, that.retryableCodes);
433527
}
434528

435529
Metadata getMetadata() {

0 commit comments

Comments
 (0)