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.AmazonServiceException;
19 import com.amazonaws.AmazonWebServiceRequest;
20 import com.amazonaws.ClientConfiguration;
21 import java.io.IOException;
22
23 /**
24  * This class includes a set of pre-defined retry policies, including default
25  * policies used by SDK.
26  */

27 public class PredefinedRetryPolicies {
28
29     /** No retry policy **/
30     public static final RetryPolicy NO_RETRY_POLICY = new RetryPolicy(
31             RetryPolicy.RetryCondition.NO_RETRY_CONDITION,
32             RetryPolicy.BackoffStrategy.NO_DELAY,
33             0,      // maxErrorRetry
34             false); // honorMaxErrorRetryInClientConfig
35
36     /* SDK default */
37
38     /** SDK default max retry count for legacy retry mode **/
39     public static final int DEFAULT_MAX_ERROR_RETRY = 3;
40
41     /** SDK default max retry count for standard retry mode **/
42     public static final int DEFAULT_MAX_ERROR_RETRY_STANDARD_MODE = 2;
43
44     /**
45      * SDK default retry policy. Amazon DynamoDB has a custom retry policy that is used when no
46      * {@link ClientConfiguration} is provided.
47      */

48     public static final RetryPolicy DEFAULT;
49
50     /* Default for DynamoDB client */
51
52     /** Default max retry count for DynamoDB client **/
53     public static final int DYNAMODB_DEFAULT_MAX_ERROR_RETRY = 10;
54
55     /** Default policy for DynamoDB client **/
56     public static final RetryPolicy DYNAMODB_DEFAULT;
57
58     /* Reusable retry policy components */
59
60     /**
61      * The SDK default retry condition, which checks for various conditions in
62      * the following order:
63      * <ul>
64      *   <li>Never retry on requests with non-repeatable content;
65      *   <li>Retry on client exceptions caused by IOException;
66      *   <li>Retry on service exceptions that are either 500 internal server
67      *       errors, 503 service unavailable errors, service throttling errors or
68      *       clock skew errors.
69      * </ul>
70      */

71     public static final RetryPolicy.RetryCondition DEFAULT_RETRY_CONDITION = new SDKDefaultRetryCondition();
72
73     /**
74      * The SDK default back-off strategy, which increases exponentially up to a max amount of delay. It also applies a larger
75      * scale factor upon service throttling exception.
76      */

77     public static final RetryPolicy.BackoffStrategy DEFAULT_BACKOFF_STRATEGY =
78             new PredefinedBackoffStrategies.SDKDefaultBackoffStrategy();
79
80     /**
81      * The SDK default back-off strategy, which increases exponentially up to a max amount of delay. It also applies a larger
82      * scale factor upon service throttling exception.
83      */

84     public static final V2CompatibleBackoffStrategy DEFAULT_BACKOFF_STRATEGY_V2 =
85             new PredefinedBackoffStrategies.SDKDefaultBackoffStrategy();
86
87     /**
88      * The default back-off strategy for DynamoDB client, which increases
89      * exponentially up to a max amount of delay. Compared to the SDK default
90      * back-off strategy, it applies a smaller scale factor.
91      */

92     public static final RetryPolicy.BackoffStrategy DYNAMODB_DEFAULT_BACKOFF_STRATEGY =
93             new PredefinedBackoffStrategies.SDKDefaultBackoffStrategy(PredefinedBackoffStrategies.DYNAMODB_DEFAULT_BASE_DELAY,
94                                                                       PredefinedBackoffStrategies.SDK_DEFAULT_THROTTLED_BASE_DELAY,
95                                                                       PredefinedBackoffStrategies.SDK_DEFAULT_MAX_BACKOFF_IN_MILLISECONDS);
96
97     static {
98         DEFAULT = getDefaultRetryPolicy();
99         DYNAMODB_DEFAULT = getDynamoDBDefaultRetryPolicy();
100     }
101
102     /**
103      * Returns the SDK default retry policy. This policy will honor the
104      * maxErrorRetry set in ClientConfiguration.
105      *
106      * @see ClientConfiguration#setMaxErrorRetry(int)
107      */

108     public static RetryPolicy getDefaultRetryPolicy() {
109         return new RetryPolicy(DEFAULT_RETRY_CONDITION,
110                                DEFAULT_BACKOFF_STRATEGY,
111                                DEFAULT_MAX_ERROR_RETRY,
112                                true,
113                                true);
114     }
115
116     /**
117      * Returns the default retry policy for DynamoDB client. This policy will
118      * honor the maxErrorRetry set in ClientConfiguration.
119      *
120      * @see ClientConfiguration#setMaxErrorRetry(int)
121      */

122     public static RetryPolicy getDynamoDBDefaultRetryPolicy() {
123         return new RetryPolicy(DEFAULT_RETRY_CONDITION,
124                                DYNAMODB_DEFAULT_BACKOFF_STRATEGY,
125                                DYNAMODB_DEFAULT_MAX_ERROR_RETRY,
126                                true,
127                                true);
128     }
129
130     /**
131      * Returns the SDK default retry policy with the specified max retry count.
132      */

133     public static RetryPolicy getDefaultRetryPolicyWithCustomMaxRetries(int maxErrorRetry) {
134         return new RetryPolicy(DEFAULT_RETRY_CONDITION,
135                                DEFAULT_BACKOFF_STRATEGY,
136                                maxErrorRetry,
137                                false);
138     }
139
140     /**
141      * Returns the default retry policy for DynamoDB client with the specified
142      * max retry count.
143      */

144     public static RetryPolicy getDynamoDBDefaultRetryPolicyWithCustomMaxRetries(int maxErrorRetry) {
145         return new RetryPolicy(DEFAULT_RETRY_CONDITION,
146                                DYNAMODB_DEFAULT_BACKOFF_STRATEGY,
147                                maxErrorRetry,
148                                false);
149     }
150
151     /**
152      * The default implementation of RetryCondition used by the SDK. User could
153      * extend this class to provide additional custom conditions.
154      * The default implementation checks for various conditions in
155      * the following order:
156      * <ul>
157      *   <li>Retry on client exceptions caused by IOException;
158      *   <li>Retry on service exceptions that are either 500 internal server
159      *       errors, 503 service unavailable errors, service throttling errors or
160      *       clock skew errors.
161      * </ul>
162      */

163     public static class SDKDefaultRetryCondition implements RetryPolicy.RetryCondition {
164
165         @Override
166         public boolean shouldRetry(AmazonWebServiceRequest originalRequest,
167                                    AmazonClientException exception,
168                                    int retriesAttempted) {
169             // Always retry on client exceptions caused by IOException
170             if (exception.getCause() instanceof IOException) return true;
171
172             // Only retry on a subset of service exceptions
173             if (exception instanceof AmazonServiceException) {
174                 AmazonServiceException ase = (AmazonServiceException)exception;
175
176                 /*
177                  * For 500 internal server errors and 503 service
178                  * unavailable errors, we want to retry, but we need to use
179                  * an exponential back-off strategy so that we don't overload
180                  * a server with a flood of retries.
181                  */

182                 if (RetryUtils.isRetryableServiceException(ase)) return true;
183
184                 /*
185                  * Throttling is reported as a 400 error from newer services. To try
186                  * and smooth out an occasional throttling error, we'll pause and
187                  * retry, hoping that the pause is long enough for the request to
188                  * get through the next time.
189                  */

190                 if (RetryUtils.isThrottlingException(ase)) return true;
191
192                 /*
193                  * Clock skew exception. If it is then we will get the time offset
194                  * between the device time and the server time to set the clock skew
195                  * and then retry the request.
196                  */

197                 if (RetryUtils.isClockSkewError(ase)) return true;
198             }
199
200             return false;
201         }
202
203     }
204 }
205