1 /*
2 * Copyright 2010-2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License").
5 * You may not use this file except in compliance with the License.
6 * A copy of the License is located at
7 *
8 * http://aws.amazon.com/apache2.0
9 *
10 * or in the "license" file accompanying this file. This file is distributed
11 * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
12 * express or implied. See the License for the specific language governing
13 * permissions and limitations under the License.
14 */
15 package com.amazonaws.retry;
16
17 import com.amazonaws.AmazonClientException;
18 import com.amazonaws.AmazonWebServiceRequest;
19 import com.amazonaws.ClientConfiguration;
20 import com.amazonaws.annotation.Immutable;
21 import com.amazonaws.annotation.SdkInternalApi;
22 import com.amazonaws.retry.internal.RetryModeResolver;
23
24 /**
25 * Retry policy that can be configured on a specific service client using
26 * {@link ClientConfiguration}. This class is immutable, therefore safe to be
27 * shared by multiple clients.
28 *
29 * @see ClientConfiguration
30 * @see PredefinedRetryPolicies
31 */
32 @Immutable
33 public final class RetryPolicy {
34
35 private static final RetryModeResolver RETRY_MODE_RESOLVER = new RetryModeResolver();
36 /**
37 * Condition on whether a request should be retried. This field
38 * should not be null.
39 */
40 private final RetryCondition retryCondition;
41
42 /**
43 * Back-off strategy to control the sleep time between retry attempts. This
44 * field should not be null.
45 */
46 private final BackoffStrategy backoffStrategy;
47
48 /**
49 * Non-negative integer indicating the max retry count.
50 */
51 private final int maxErrorRetry;
52
53 /**
54 * Whether this retry policy should honor the max error retry set in ClientConfiguration.
55 * @see ClientConfiguration#setMaxErrorRetry(int)
56 */
57 private final boolean honorMaxErrorRetryInClientConfig;
58
59 /**
60 * The retry mode to use
61 */
62 private final RetryMode retryMode;
63
64 /**
65 * Whether it should honor the default max error retry in {@link RetryMode}
66 */
67 private final boolean honorDefaultMaxErrorRetryInRetryMode;
68
69 /**
70 * Constructs a new retry policy. See {@link PredefinedRetryPolicies} for
71 * some pre-defined policy components, and also the default policies used by
72 * SDK.
73 *
74 * @param retryCondition
75 * Retry condition on whether a specific request and exception
76 * should be retried. If null value is specified, the SDK'
77 * default retry condition is used.
78 * @param backoffStrategy
79 * Back-off strategy for controlling how long the next retry
80 * should wait. If null value is specified, the SDK' default
81 * exponential back-off strategy is used.
82 * @param maxErrorRetry
83 * Maximum number of retry attempts for failed requests.
84 * @param honorMaxErrorRetryInClientConfig
85 * Whether this retry policy should honor the max error retry set
86 * by {@link ClientConfiguration#setMaxErrorRetry(int)}
87 * @see ClientConfiguration
88 * @see PredefinedRetryPolicies
89 */
90 public RetryPolicy(RetryCondition retryCondition,
91 BackoffStrategy backoffStrategy,
92 int maxErrorRetry,
93 boolean honorMaxErrorRetryInClientConfig) {
94 this(retryCondition, backoffStrategy, maxErrorRetry, honorMaxErrorRetryInClientConfig, false);
95 }
96
97 @SdkInternalApi
98 public RetryPolicy(RetryCondition retryCondition,
99 BackoffStrategy backoffStrategy,
100 int maxErrorRetry,
101 boolean honorMaxErrorRetryInClientConfig,
102 boolean honorDefaultMaxErrorRetryInRetryMode) {
103 this(retryCondition, backoffStrategy, maxErrorRetry, honorMaxErrorRetryInClientConfig, null, honorDefaultMaxErrorRetryInRetryMode);
104 }
105
106 public RetryPolicy(RetryCondition retryCondition,
107 BackoffStrategy backoffStrategy,
108 int maxErrorRetry,
109 boolean honorMaxErrorRetryInClientConfig,
110 RetryMode retryMode) {
111 this(retryCondition, backoffStrategy, maxErrorRetry, honorMaxErrorRetryInClientConfig, retryMode, false);
112 }
113
114 @SdkInternalApi
115 RetryPolicy(RetryCondition retryCondition,
116 BackoffStrategy backoffStrategy,
117 int maxErrorRetry,
118 boolean honorMaxErrorRetryInClientConfig,
119 RetryMode retryMode,
120 boolean honorDefaultMaxErrorRetryInRetryMode) {
121 if (retryCondition == null) {
122 retryCondition = PredefinedRetryPolicies.DEFAULT_RETRY_CONDITION;
123 }
124 if (backoffStrategy == null) {
125 backoffStrategy = PredefinedRetryPolicies.DEFAULT_BACKOFF_STRATEGY;
126 }
127 if (maxErrorRetry < 0) {
128 throw new IllegalArgumentException("Please provide a non-negative value for maxErrorRetry.");
129 }
130
131 this.honorDefaultMaxErrorRetryInRetryMode = honorDefaultMaxErrorRetryInRetryMode;
132 this.retryCondition = retryCondition;
133 this.backoffStrategy = backoffStrategy;
134 this.maxErrorRetry = maxErrorRetry;
135 this.honorMaxErrorRetryInClientConfig = honorMaxErrorRetryInClientConfig;
136 this.retryMode = retryMode != null ? retryMode : RETRY_MODE_RESOLVER.retryMode();
137 }
138
139 /**
140 * Returns the retry condition included in this retry policy.
141 *
142 * @return The retry condition included in this retry policy.
143 */
144 public RetryCondition getRetryCondition() {
145 return retryCondition;
146 }
147
148 /**
149 * Returns the back-off strategy included in this retry policy.
150 *
151 * @return The back-off strategy included in this retry policy.
152 */
153 public BackoffStrategy getBackoffStrategy() {
154 return backoffStrategy;
155 }
156
157 /**
158 * Returns the maximum number of retry attempts.
159 *
160 * @return The maximum number of retry attempts.
161 */
162 public int getMaxErrorRetry() {
163 return maxErrorRetry;
164 }
165
166 /**
167 * Returns whether this retry policy should honor the max error retry set in
168 * ClientConfiguration.
169 *
170 * @return Whether this retry policy should honor the max error retry set in
171 * ClientConfiguration
172 * @see ClientConfiguration#setMaxErrorRetry(int)
173 */
174 public boolean isMaxErrorRetryInClientConfigHonored() {
175 return honorMaxErrorRetryInClientConfig;
176 }
177
178 /**
179 * Returns the {@link RetryMode} to be used.
180 *
181 * @return retryMode
182 */
183 public RetryMode getRetryMode() {
184 return retryMode;
185 }
186
187 /**
188 * @return Whether the default max error in retry mode should be honored.
189 */
190 boolean isDefaultMaxErrorRetryInRetryModeHonored() {
191 return honorDefaultMaxErrorRetryInRetryMode;
192 }
193
194 /**
195 * The hook for providing custom condition on whether a failed request
196 * should be retried.
197 */
198 public interface RetryCondition {
199 RetryCondition NO_RETRY_CONDITION = new RetryCondition() {
200 @Override
201 public boolean shouldRetry(AmazonWebServiceRequest originalRequest,
202 AmazonClientException exception,
203 int retriesAttempted) {
204 return false;
205 }
206 };
207
208 /**
209 * Returns whether a failed request should be retried according to the
210 * given request context. In the following circumstances, the request
211 * will fail directly without consulting this method:
212 * <ul>
213 * <li> if it has already reached the max retry limit,
214 * <li> if the request contains non-repeatable content,
215 * <li> if any RuntimeException or Error is thrown when executing the request.
216 * </ul>
217 *
218 * @param originalRequest
219 * The original request object being executed. For
220 * performance reason, this object is not a defensive copy,
221 * and caller should not attempt to modify its data.
222 * @param exception
223 * The exception from the failed request, represented as an
224 * AmazonClientException object. There are two types of
225 * exception that will be passed to this method:
226 * <ul>
227 * <li>AmazonServiceException (sub-class of
228 * AmazonClientException) indicating a service error
229 * <li>AmazonClientException caused by an IOException when
230 * executing the HTTP request.
231 * </ul>
232 * Any other exceptions are regarded as unexpected failures
233 * and are thrown immediately without any retry. For
234 * performance reason, this object is not a defensive copy,
235 * and caller should not attempt to modify its data.
236 * @param retriesAttempted
237 * The number of times the current request has been
238 * attempted.
239 *
240 * @return True if the failed request should be retried.
241 */
242 boolean shouldRetry(AmazonWebServiceRequest originalRequest,
243 AmazonClientException exception,
244 int retriesAttempted);
245
246 }
247
248 /**
249 * The hook for providing custom back-off strategy to control the sleep time
250 * between retries.
251 */
252 public interface BackoffStrategy {
253 RetryPolicy.BackoffStrategy NO_DELAY = new BackoffStrategy() {
254 @Override
255 public long delayBeforeNextRetry(AmazonWebServiceRequest originalRequest,
256 AmazonClientException exception,
257 int retriesAttempted) {
258 return 0;
259 }
260 };
261
262 /**
263 * Returns the delay (in milliseconds) before next retry attempt.
264 *
265 * @param originalRequest
266 * The original request object being executed. For
267 * performance reason, this object is not a defensive copy,
268 * and caller should not attempt to modify its data.
269 * @param exception
270 * The exception from the failed request, represented as an
271 * AmazonClientException object. There are two types of
272 * exception that will be passed to this method:
273 * <ul>
274 * <li>AmazonServiceException (sub-class of
275 * AmazonClientException) indicating a service error
276 * <li>AmazonClientException caused by an IOException when
277 * executing the HTTP request.
278 * </ul>
279 * Any other exceptions are regarded as unexpected failures
280 * and are thrown immediately without any retry. For
281 * performance reason, this object is not a defensive copy,
282 * and caller should not attempt to modify its data.
283 * @param retriesAttempted
284 * The number of times the current request has been attempted
285 * (not including the next attempt after the delay).
286 *
287 * @return The delay (in milliseconds) before next retry attempt.
288 */
289 long delayBeforeNextRetry(AmazonWebServiceRequest originalRequest,
290 AmazonClientException exception,
291 int retriesAttempted);
292 }
293 }
294