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