1 /* 2 * Copyright 2016 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.InternalExtensionOnly; 33 import com.google.api.gax.retrying.RetrySettings; 34 import com.google.common.base.MoreObjects; 35 import com.google.common.collect.ImmutableSet; 36 import com.google.common.collect.Sets; 37 import java.util.Set; 38 import org.threeten.bp.Duration; 39 40 /** 41 * A base settings class to configure a UnaryCallable. An instance of UnaryCallSettings is not 42 * sufficient on its own to construct a UnaryCallable; a concrete derived type is necessary. 43 * 44 * <p>This base class includes settings that are applicable to all calls, which currently is just 45 * retry settings. 46 * 47 * <p>Retry configuration is composed of two parts: the retryable codes, and the retry settings. The 48 * retryable codes indicate which codes cause a retry to occur, and the retry settings configure the 49 * retry logic when the retry needs to happen. To turn off retries, set the retryable codes to the 50 * empty set. 51 * 52 * <p>UnaryCallSettings contains a concrete builder class, {@link UnaryCallSettings.Builder}. This 53 * builder class cannot be used to create an instance of UnaryCallSettings, because 54 * UnaryCallSettings is an abstract class. 55 */ 56 @InternalExtensionOnly 57 public class UnaryCallSettings<RequestT, ResponseT> { 58 59 private final ImmutableSet<StatusCode.Code> retryableCodes; 60 private final RetrySettings retrySettings; 61 62 /** 63 * See the class documentation of {@link UnaryCallSettings} for a description of what retryable 64 * codes do. 65 */ getRetryableCodes()66 public final Set<StatusCode.Code> getRetryableCodes() { 67 return retryableCodes; 68 } 69 70 /** 71 * See the class documentation of {@link UnaryCallSettings} for a description of what retry 72 * settings do. 73 */ getRetrySettings()74 public final RetrySettings getRetrySettings() { 75 return retrySettings; 76 } 77 newUnaryCallSettingsBuilder()78 public static <RequestT, ResponseT> Builder<RequestT, ResponseT> newUnaryCallSettingsBuilder() { 79 return new Builder<>(); 80 } 81 toBuilder()82 public Builder<RequestT, ResponseT> toBuilder() { 83 return new Builder<>(this); 84 } 85 UnaryCallSettings(Builder<RequestT, ResponseT> builder)86 protected UnaryCallSettings(Builder<RequestT, ResponseT> builder) { 87 this.retryableCodes = ImmutableSet.copyOf(builder.retryableCodes); 88 this.retrySettings = builder.retrySettingsBuilder.build(); 89 } 90 91 @Override toString()92 public String toString() { 93 return MoreObjects.toStringHelper(this) 94 .add("retryableCodes", retryableCodes) 95 .add("retrySettings", retrySettings) 96 .toString(); 97 } 98 99 @Override hashCode()100 public int hashCode() { 101 int prime = 43; 102 int result = prime + ((retrySettings == null) ? 0 : retrySettings.hashCode()); 103 result = prime * result + ((retryableCodes == null) ? 0 : retryableCodes.hashCode()); 104 return result; 105 } 106 107 @Override equals(Object obj)108 public boolean equals(Object obj) { 109 if (this == obj) { 110 return true; 111 } else if (obj == null) { 112 return false; 113 } else if (getClass() != obj.getClass()) { 114 return false; 115 } 116 117 UnaryCallSettings<?, ?> other = (UnaryCallSettings<?, ?>) obj; 118 if (!retrySettings.equals(other.retrySettings)) { 119 return false; 120 } else if (!retryableCodes.equals(other.retryableCodes)) { 121 return false; 122 } 123 return true; 124 } 125 126 /** 127 * A base builder class for {@link UnaryCallSettings}. This class should not be used to create an 128 * instance of the base class UnaryCallSettings. See the class documentation of {@link 129 * UnaryCallSettings} for a description of the different values that can be set, and for a 130 * description of when this builder may be used. Builders for concrete derived classes can be used 131 * to create instances of those classes. 132 */ 133 public static class Builder<RequestT, ResponseT> { 134 135 private Set<StatusCode.Code> retryableCodes; 136 private RetrySettings.Builder retrySettingsBuilder; 137 Builder()138 protected Builder() { 139 retryableCodes = Sets.newHashSet(); 140 retrySettingsBuilder = RetrySettings.newBuilder(); 141 } 142 Builder(UnaryCallSettings<RequestT, ResponseT> unaryCallSettings)143 protected Builder(UnaryCallSettings<RequestT, ResponseT> unaryCallSettings) { 144 setRetryableCodes(unaryCallSettings.retryableCodes); 145 setRetrySettings(unaryCallSettings.getRetrySettings()); 146 } 147 148 /** 149 * See the class documentation of {@link UnaryCallSettings} for a description of what retryable 150 * codes do. 151 */ setRetryableCodes( Set<StatusCode.Code> retryableCodes)152 public UnaryCallSettings.Builder<RequestT, ResponseT> setRetryableCodes( 153 Set<StatusCode.Code> retryableCodes) { 154 this.retryableCodes = Sets.newHashSet(retryableCodes); 155 return this; 156 } 157 158 /** 159 * See the class documentation of {@link UnaryCallSettings} for a description of what retryable 160 * codes do. 161 */ setRetryableCodes( StatusCode.Code... codes)162 public UnaryCallSettings.Builder<RequestT, ResponseT> setRetryableCodes( 163 StatusCode.Code... codes) { 164 this.setRetryableCodes(Sets.newHashSet(codes)); 165 return this; 166 } 167 168 /** 169 * Returns the underlying {@link RetrySettings.Builder}, which allows callers to augment the 170 * existing {@link RetrySettings}. 171 */ retrySettings()172 public RetrySettings.Builder retrySettings() { 173 return this.retrySettingsBuilder; 174 } 175 176 /** 177 * Replaces the {@link RetrySettings} for the associated {@link UnaryCallable}. 178 * 179 * <p>When using the method, make sure that the {@link RetrySettings} are complete. For example, 180 * the following code will disable retries because the retry delay is not set: 181 * 182 * <pre>{@code 183 * stubSettings.setRetrySettings( 184 * RetrySettings.newBuilder() 185 * .setTotalTimeout(Duration.ofSeconds(10) 186 * ); 187 * }</pre> 188 * 189 * @see #retrySettings() 190 */ setRetrySettings( RetrySettings retrySettings)191 public UnaryCallSettings.Builder<RequestT, ResponseT> setRetrySettings( 192 RetrySettings retrySettings) { 193 this.retrySettingsBuilder = retrySettings.toBuilder(); 194 return this; 195 } 196 197 /** Disables retries and sets the RPC timeout. */ setSimpleTimeoutNoRetries( Duration timeout)198 public UnaryCallSettings.Builder<RequestT, ResponseT> setSimpleTimeoutNoRetries( 199 Duration timeout) { 200 setRetryableCodes(); 201 setRetrySettings( 202 RetrySettings.newBuilder() 203 .setTotalTimeout(timeout) 204 .setInitialRetryDelay(Duration.ZERO) 205 .setRetryDelayMultiplier(1) 206 .setMaxRetryDelay(Duration.ZERO) 207 .setInitialRpcTimeout(timeout) 208 .setRpcTimeoutMultiplier(1) 209 .setMaxRpcTimeout(timeout) 210 .setMaxAttempts(1) 211 .build()); 212 return this; 213 } 214 215 /** 216 * See the class documentation of {@link UnaryCallSettings} for a description of what retryable 217 * codes do. 218 */ getRetryableCodes()219 public Set<StatusCode.Code> getRetryableCodes() { 220 return this.retryableCodes; 221 } 222 223 /** 224 * Returns an immutable {@link RetrySettings} currently set in this Builder. 225 * 226 * <p>Unlike {@link #retrySettings()}, objects returned by this method are frozen in time. 227 */ getRetrySettings()228 public RetrySettings getRetrySettings() { 229 return this.retrySettingsBuilder.build(); 230 } 231 232 /** 233 * Builds an instance of the containing class. This operation is unsupported on the abstract 234 * base class UnaryCallSettings, but is valid on concrete derived classes. 235 */ build()236 public UnaryCallSettings<RequestT, ResponseT> build() { 237 return new UnaryCallSettings<>(this); 238 } 239 } 240 } 241