• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2017 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.rpc;
31 
32 import com.google.api.core.BetaApi;
33 import com.google.api.core.InternalExtensionOnly;
34 import com.google.api.gax.retrying.RetrySettings;
35 import com.google.api.gax.retrying.RetryingContext;
36 import com.google.api.gax.rpc.StatusCode.Code;
37 import com.google.api.gax.tracing.ApiTracer;
38 import com.google.auth.Credentials;
39 import com.google.common.base.Preconditions;
40 import java.util.List;
41 import java.util.Map;
42 import java.util.Set;
43 import javax.annotation.Nonnull;
44 import javax.annotation.Nullable;
45 import org.threeten.bp.Duration;
46 
47 /**
48  * Context for an API call.
49  *
50  * <p>An API call can be composed of many RPCs (in case of retries). This class contains settings
51  * for both: API calls and RPCs.
52  *
53  * <p>Implementations need to be immutable because default instances are stored in callable objects.
54  *
55  * <p>This is transport specific and each transport has an implementation with its own options.
56  */
57 @InternalExtensionOnly
58 public interface ApiCallContext extends RetryingContext {
59 
60   /** Returns a new ApiCallContext with the given credentials set. */
withCredentials(Credentials credentials)61   ApiCallContext withCredentials(Credentials credentials);
62 
63   /** Returns a new ApiCallContext with the given channel set. */
withTransportChannel(TransportChannel channel)64   ApiCallContext withTransportChannel(TransportChannel channel);
65 
66   /**
67    * Returns a new ApiCallContext with the given timeout set.
68    *
69    * <p>This sets the maximum amount of time a single unary RPC attempt can take. If retries are
70    * enabled, then this can take much longer, as each RPC attempt will have the same constant
71    * timeout. Unlike a deadline, timeouts are relative durations that are measure from the beginning
72    * of each RPC attempt. Please note that this limits the duration of a server streaming RPC as
73    * well.
74    *
75    * <p>If a method has default {@link com.google.api.gax.retrying.RetrySettings}, the max attempts
76    * and/or total timeout is still respected when scheduling each RPC attempt.
77    */
withTimeout(@ullable Duration timeout)78   ApiCallContext withTimeout(@Nullable Duration timeout);
79 
80   /** Returns the configured per-RPC timeout. */
81   @Nullable
getTimeout()82   Duration getTimeout();
83 
84   /**
85    * Returns a new ApiCallContext with the given stream timeout set.
86    *
87    * <p>This timeout only applies to a {@link ServerStreamingCallable}s. It limits the maximum
88    * amount of time that can pass between demand being signaled via {@link
89    * StreamController#request(int)} and actual message delivery to {@link
90    * ResponseObserver#onResponse(Object)}. Or, in the case of automatic flow control, since the last
91    * message was delivered to {@link ResponseObserver#onResponse(Object)}. This is useful to detect
92    * server or connection stalls. When the timeout has been reached, the stream will be closed with
93    * a retryable {@link WatchdogTimeoutException} and a status of {@link StatusCode.Code#ABORTED}.
94    *
95    * <p>A value of {@link Duration#ZERO}, disables the streaming wait timeout and a null value will
96    * use the default in the callable.
97    *
98    * <p>Please note that this timeout is best effort and the maximum resolution is configured in
99    * {@link StubSettings#getStreamWatchdogCheckInterval()}.
100    */
withStreamWaitTimeout(@ullable Duration streamWaitTimeout)101   ApiCallContext withStreamWaitTimeout(@Nullable Duration streamWaitTimeout);
102 
103   /**
104    * Return the stream wait timeout set for this context.
105    *
106    * @see #withStreamWaitTimeout(Duration)
107    */
108   @Nullable
getStreamWaitTimeout()109   Duration getStreamWaitTimeout();
110 
111   /**
112    * Returns a new ApiCallContext with the given stream idle timeout set.
113    *
114    * <p>This timeout only applies to a {@link ServerStreamingCallable}s. It limits the maximum
115    * amount of timeout that can pass between a message being received by {@link
116    * ResponseObserver#onResponse(Object)} and demand being signaled via {@link
117    * StreamController#request(int)}. Please note that this timeout is best effort and the maximum
118    * resolution configured in {@link StubSettings#getStreamWatchdogCheckInterval()}. This is useful
119    * to clean up streams that were partially read but never closed. When the timeout has been
120    * reached, the stream will be closed with a nonretryable {@link WatchdogTimeoutException} and a
121    * status of {@link StatusCode.Code#ABORTED}.
122    *
123    * <p>A value of {@link Duration#ZERO}, disables the streaming idle timeout and a null value will
124    * use the default in the callable.
125    *
126    * <p>Please note that this timeout is best effort and the maximum resolution is configured in
127    * {@link StubSettings#getStreamWatchdogCheckInterval()}.
128    */
withStreamIdleTimeout(@ullable Duration streamIdleTimeout)129   ApiCallContext withStreamIdleTimeout(@Nullable Duration streamIdleTimeout);
130 
131   /**
132    * The stream idle timeout set for this context.
133    *
134    * @see #withStreamIdleTimeout(Duration)
135    */
136   @Nullable
getStreamIdleTimeout()137   Duration getStreamIdleTimeout();
138 
139   /**
140    * The {@link ApiTracer} that was previously set for this context.
141    *
142    * <p>The {@link ApiTracer} will be used to trace the current operation and to annotate various
143    * events like retries.
144    */
145   @BetaApi("The surface for tracing is not stable yet and may change in the future")
146   @Nonnull
getTracer()147   ApiTracer getTracer();
148 
149   /**
150    * Returns a new {@link ApiCallContext} with the given {@link ApiTracer}.
151    *
152    * <p>The {@link ApiTracer} will be used to trace the current operation and to annotate various
153    * events like retries.
154    *
155    * @param tracer the {@link ApiTracer} to set.
156    */
157   @BetaApi("The surface for tracing is not stable yet and may change in the future")
withTracer(@onnull ApiTracer tracer)158   ApiCallContext withTracer(@Nonnull ApiTracer tracer);
159 
160   /**
161    * Returns a new ApiCallContext with the given {@link RetrySettings} set.
162    *
163    * <p>This sets the {@link RetrySettings} to use for the RPC. These settings will work in
164    * combination with either the default retryable codes for the RPC, or the retryable codes
165    * supplied through {@link #withRetryableCodes(Set)}. Calling {@link
166    * #withRetrySettings(RetrySettings)} on an RPC that does not include {@link
167    * Code#DEADLINE_EXCEEDED} as one of its retryable codes (or without calling {@link
168    * #withRetryableCodes(Set)} with a set that includes at least {@link Code#DEADLINE_EXCEEDED})
169    * will effectively only set a single timeout that is equal to {@link
170    * RetrySettings#getInitialRpcTimeout()}. If this timeout is exceeded, the RPC will not be retried
171    * and will fail with {@link Code#DEADLINE_EXCEEDED}.
172    *
173    * <p>Example usage:
174    *
175    * <pre>{@code
176    * ApiCallContext context = GrpcCallContext.createDefault()
177    *   .withRetrySettings(RetrySettings.newBuilder()
178    *     .setInitialRetryDelay(Duration.ofMillis(10L))
179    *     .setInitialRpcTimeout(Duration.ofMillis(100L))
180    *     .setMaxAttempts(10)
181    *     .setMaxRetryDelay(Duration.ofSeconds(10L))
182    *     .setMaxRpcTimeout(Duration.ofSeconds(30L))
183    *     .setRetryDelayMultiplier(1.4)
184    *     .setRpcTimeoutMultiplier(1.5)
185    *     .setTotalTimeout(Duration.ofMinutes(10L))
186    *     .build())
187    *   .withRetryableCodes(Sets.newSet(
188    *     StatusCode.Code.UNAVAILABLE,
189    *     StatusCode.Code.DEADLINE_EXCEEDED));
190    * }</pre>
191    *
192    * Setting a logical call timeout for the context can be done similarly with {@link
193    * RetrySettings.Builder#setLogicalTimeout(Duration timeout)}.
194    *
195    * <p>Example usage:
196    *
197    * <pre>{@code
198    * ApiCallContext context = GrpcCallContext.createDefault()
199    *   .withRetrySettings(RetrySettings.newBuilder()
200    *     .setInitialRetryDelay(Duration.ofMillis(10L))
201    *     .setMaxRetryDelay(Duration.ofSeconds(10L))
202    *     .setRetryDelayMultiplier(1.4)
203    *     .setMaxAttempts(10)
204    *     .setLogicalTimeout(Duration.ofSeconds(30L))
205    *     .build());
206    * }</pre>
207    */
208   @BetaApi
withRetrySettings(RetrySettings retrySettings)209   ApiCallContext withRetrySettings(RetrySettings retrySettings);
210 
211   /**
212    * Returns a new ApiCallContext with the given retryable codes set.
213    *
214    * <p>This sets the retryable codes to use for the RPC. These settings will work in combination
215    * with either the default {@link RetrySettings} for the RPC, or the {@link RetrySettings}
216    * supplied through {@link #withRetrySettings(RetrySettings)}.
217    *
218    * <p>Setting a non-empty set of retryable codes for an RPC that is not already retryable by
219    * default, will not have any effect and the RPC will NOT be retried. This option can only be used
220    * to change which codes are considered retryable for an RPC that already has at least one
221    * retryable code in its default settings.
222    */
223   @BetaApi
withRetryableCodes(Set<StatusCode.Code> retryableCodes)224   ApiCallContext withRetryableCodes(Set<StatusCode.Code> retryableCodes);
225 
226   /** If inputContext is not null, returns it; if it is null, returns the present instance. */
nullToSelf(ApiCallContext inputContext)227   ApiCallContext nullToSelf(ApiCallContext inputContext);
228 
229   /**
230    * For any values in {@code inputCallContext} that are not null, override the corresponding values
231    * in the present instance.
232    */
merge(ApiCallContext inputCallContext)233   ApiCallContext merge(ApiCallContext inputCallContext);
234 
235   /** Return a new ApiCallContext with the extraHeaders merged into the present instance. */
236   @BetaApi("The surface for extra headers is not stable yet and may change in the future.")
withExtraHeaders(Map<String, List<String>> extraHeaders)237   ApiCallContext withExtraHeaders(Map<String, List<String>> extraHeaders);
238 
239   /** Return the extra headers set for this context. */
240   @BetaApi("The surface for extra headers is not stable yet and may change in the future.")
getExtraHeaders()241   Map<String, List<String>> getExtraHeaders();
242 
243   /**
244    * Return a new ApiCallContext with additional option merged into the present instance. Any
245    * existing value of the key is overwritten.
246    */
247   @BetaApi("The surface for call context options is not stable yet and may change in the future.")
withOption(Key<T> key, T value)248   <T> ApiCallContext withOption(Key<T> key, T value);
249 
250   /** Return the api call context option set for this context. */
251   @SuppressWarnings("unchecked")
252   @BetaApi("The surface for call context options is not stable yet and may change in the future.")
getOption(Key<T> key)253   <T> T getOption(Key<T> key);
254 
255   /** Key for api call context options key-value pair. */
256   final class Key<T> {
257     private final String name;
258 
Key(String name)259     private Key(String name) {
260       this.name = name;
261     }
262 
263     /** Factory method for creating instances of {@link Key}. */
create(String name)264     public static <T> Key<T> create(String name) {
265       Preconditions.checkNotNull(name, "Key name cannot be null.");
266       return new Key<>(name);
267     }
268   }
269 }
270