-
Notifications
You must be signed in to change notification settings - Fork 2.8k
/
PredefinedRetryPolicies.java
273 lines (227 loc) · 10.8 KB
/
PredefinedRetryPolicies.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
/*
* Copyright 2010-2015 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License").
* You may not use this file except in compliance with the License.
* A copy of the License is located at
*
* http://aws.amazon.com/apache2.0
*
* or in the "license" file accompanying this file. This file is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/
package com.amazonaws.retry;
import java.io.IOException;
import java.util.Random;
import org.apache.http.HttpStatus;
import com.amazonaws.AmazonClientException;
import com.amazonaws.AmazonServiceException;
import com.amazonaws.AmazonWebServiceRequest;
import com.amazonaws.ClientConfiguration;
/**
* This class includes a set of pre-defined retry policies, including default
* policies used by SDK.
*/
public class PredefinedRetryPolicies {
/** No retry policy **/
public static final RetryPolicy NO_RETRY_POLICY = new RetryPolicy(
RetryPolicy.RetryCondition.NO_RETRY_CONDITION,
RetryPolicy.BackoffStrategy.NO_DELAY,
0, // maxErrorRetry
false); // honorMaxErrorRetryInClientConfig
/* SDK default */
/** SDK default max retry count **/
public static final int DEFAULT_MAX_ERROR_RETRY = 3;
/**
* SDK default retry policy (except for AmazonDynamoDBClient,
* whose constructor will replace the DEFAULT with DYNAMODB_DEFAULT.)
*/
public static final RetryPolicy DEFAULT;
/* Default for DynamoDB client */
/** Default max retry count for DynamoDB client **/
public static final int DYNAMODB_DEFAULT_MAX_ERROR_RETRY = 10;
/** Default policy for DynamoDB client **/
public static final RetryPolicy DYNAMODB_DEFAULT;
/* Reusable retry policy components */
/**
* The SDK default retry condition, which checks for various conditions in
* the following order:
* <ul>
* <li>Never retry on requests with non-repeatable content;
* <li>Retry on client exceptions caused by IOException;
* <li>Retry on service exceptions that are either 500 internal server
* errors, 503 service unavailable errors, service throttling errors or
* clock skew errors.
* </ul>
*/
public static final RetryPolicy.RetryCondition DEFAULT_RETRY_CONDITION = new SDKDefaultRetryCondition();
/**
* The SDK default back-off strategy, which increases exponentially up to a
* max amount of delay. It also applies a larger scale factor upon service
* throttling exception.
*/
public static final RetryPolicy.BackoffStrategy DEFAULT_BACKOFF_STRATEGY = new SDKDefaultBackoffStrategy();
/**
* The default back-off strategy for DynamoDB client, which increases
* exponentially up to a max amount of delay. Compared to the SDK default
* back-off strategy, it applies a smaller scale factor.
*/
public static final RetryPolicy.BackoffStrategy DYNAMODB_DEFAULT_BACKOFF_STRATEGY = new DynamoDBDefaultBackoffStrategy();
static {
DEFAULT = getDefaultRetryPolicy();
DYNAMODB_DEFAULT = getDynamoDBDefaultRetryPolicy();
}
/**
* Returns the SDK default retry policy. This policy will honor the
* maxErrorRetry set in ClientConfiguration.
*
* @see ClientConfiguration#setMaxErrorRetry(int)
*/
public static RetryPolicy getDefaultRetryPolicy() {
return new RetryPolicy(DEFAULT_RETRY_CONDITION,
DEFAULT_BACKOFF_STRATEGY,
DEFAULT_MAX_ERROR_RETRY,
true);
}
/**
* Returns the default retry policy for DynamoDB client. This policy will
* honor the maxErrorRetry set in ClientConfiguration.
*
* @see ClientConfiguration#setMaxErrorRetry(int)
*/
public static RetryPolicy getDynamoDBDefaultRetryPolicy() {
return new RetryPolicy(DEFAULT_RETRY_CONDITION,
DYNAMODB_DEFAULT_BACKOFF_STRATEGY,
DYNAMODB_DEFAULT_MAX_ERROR_RETRY,
true);
}
/**
* Returns the SDK default retry policy with the specified max retry count.
*/
public static RetryPolicy getDefaultRetryPolicyWithCustomMaxRetries(int maxErrorRetry) {
return new RetryPolicy(DEFAULT_RETRY_CONDITION,
DEFAULT_BACKOFF_STRATEGY,
maxErrorRetry,
false);
}
/**
* Returns the default retry policy for DynamoDB client with the specified
* max retry count.
*/
public static RetryPolicy getDynamoDBDefaultRetryPolicyWithCustomMaxRetries(int maxErrorRetry) {
return new RetryPolicy(DEFAULT_RETRY_CONDITION,
DYNAMODB_DEFAULT_BACKOFF_STRATEGY,
maxErrorRetry,
false);
}
/**
* The default implementation of RetryCondition used by the SDK. User could
* extend this class to provide additional custom conditions.
* The default implementation checks for various conditions in
* the following order:
* <ul>
* <li>Retry on client exceptions caused by IOException;
* <li>Retry on service exceptions that are either 500 internal server
* errors, 503 service unavailable errors, service throttling errors or
* clock skew errors.
* </ul>
*/
public static class SDKDefaultRetryCondition implements RetryPolicy.RetryCondition {
@Override
public boolean shouldRetry(AmazonWebServiceRequest originalRequest,
AmazonClientException exception,
int retriesAttempted) {
// Always retry on client exceptions caused by IOException
if (exception.getCause() instanceof IOException) return true;
// Only retry on a subset of service exceptions
if (exception instanceof AmazonServiceException) {
AmazonServiceException ase = (AmazonServiceException)exception;
/*
* For 500 internal server errors and 503 service
* unavailable errors, we want to retry, but we need to use
* an exponential back-off strategy so that we don't overload
* a server with a flood of retries.
*/
if (ase.getStatusCode() == HttpStatus.SC_INTERNAL_SERVER_ERROR
|| ase.getStatusCode() == HttpStatus.SC_SERVICE_UNAVAILABLE) {
return true;
}
/*
* Throttling is reported as a 400 error from newer services. To try
* and smooth out an occasional throttling error, we'll pause and
* retry, hoping that the pause is long enough for the request to
* get through the next time.
*/
if (RetryUtils.isThrottlingException(ase)) return true;
/*
* Clock skew exception. If it is then we will get the time offset
* between the device time and the server time to set the clock skew
* and then retry the request.
*/
if (RetryUtils.isClockSkewError(ase)) return true;
}
return false;
}
}
/** A private class that implements the default back-off strategy. **/
private static class SDKDefaultBackoffStrategy implements RetryPolicy.BackoffStrategy {
/** Base sleep time (milliseconds) for general exceptions. **/
private static final int SCALE_FACTOR = 300;
/** Base sleep time (milliseconds) for throttling exceptions. **/
private static final int THROTTLING_SCALE_FACTOR = 500;
private static final int THROTTLING_SCALE_FACTOR_RANDOM_RANGE = THROTTLING_SCALE_FACTOR / 4;
/** Maximum exponential back-off time before retrying a request */
private static final int MAX_BACKOFF_IN_MILLISECONDS = 20 * 1000;
/**
* Maximum number of retries before the max backoff will be hit. This is
* calculated via log_2(MAX_BACKOFF_IN_MILLISECONDS / SCALE_FACTOR)
* based on the code below.
*/
private static final int MAX_RETRIES_BEFORE_MAX_BACKOFF = 6;
/** For generating a random scale factor **/
private final Random random = new Random();
/** {@inheritDoc} */
@Override
public final long delayBeforeNextRetry(AmazonWebServiceRequest originalRequest,
AmazonClientException exception,
int retriesAttempted) {
if (retriesAttempted < 0) return 0;
if (retriesAttempted > MAX_RETRIES_BEFORE_MAX_BACKOFF) return MAX_BACKOFF_IN_MILLISECONDS;
int scaleFactor;
if (exception instanceof AmazonServiceException
&& RetryUtils.isThrottlingException((AmazonServiceException)exception)) {
scaleFactor = THROTTLING_SCALE_FACTOR + random.nextInt(THROTTLING_SCALE_FACTOR_RANDOM_RANGE);
} else {
scaleFactor = SCALE_FACTOR;
}
long delay = (1L << retriesAttempted) * scaleFactor;
delay = Math.min(delay, MAX_BACKOFF_IN_MILLISECONDS);
return delay;
}
}
/** A private class that implements the default back-off strategy for DynamoDB client. **/
private static class DynamoDBDefaultBackoffStrategy implements RetryPolicy.BackoffStrategy {
/** Base sleep time (milliseconds) **/
private static final int SCALE_FACTOR = 25;
/** Maximum exponential back-off time before retrying a request */
private static final int MAX_BACKOFF_IN_MILLISECONDS = 20 * 1000;
/**
* Maximum number of retries before the max backoff will be hit. This is
* calculated via log_2(MAX_BACKOFF_IN_MILLISECONDS / SCALE_FACTOR)
* based on the code below.
*/
private static final int MAX_RETRIES_BEFORE_MAX_BACKOFF = 9;
@Override
public final long delayBeforeNextRetry(AmazonWebServiceRequest originalRequest,
AmazonClientException exception,
int retriesAttempted) {
if (retriesAttempted < 0) return 0;
if (retriesAttempted > MAX_RETRIES_BEFORE_MAX_BACKOFF) return MAX_BACKOFF_IN_MILLISECONDS;
long delay = (1L << retriesAttempted) * SCALE_FACTOR;
delay = Math.min(delay, MAX_BACKOFF_IN_MILLISECONDS);
return delay;
}
}
}