Skip to content

Commit a806cd7

Browse files
authored
Add standard retry strategy (#3931)
* Add standard retry strategy * Fix the AcquireInitialTokenRequestImpl API annotation Also add the package to the test/tests-coverage-reporting/pom.xml to get coverage reporting
1 parent f40dd27 commit a806cd7

26 files changed

+1989
-25
lines changed

core/pom.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@
4747
<module>endpoints-spi</module>
4848
<module>imds</module>
4949
<module>retries-api</module>
50+
<module>retries</module>
5051
</modules>
5152

5253
<dependencyManagement>

core/retries-api/src/main/java/software/amazon/awssdk/retries/api/AcquireInitialTokenRequest.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717

1818
import software.amazon.awssdk.annotations.SdkPublicApi;
1919
import software.amazon.awssdk.annotations.ThreadSafe;
20+
import software.amazon.awssdk.retries.api.internal.AcquireInitialTokenRequestImpl;
2021

2122
/**
2223
* Encapsulates the abstract scope to start the attempts about to be executed using a retry strategy.
@@ -33,4 +34,11 @@ public interface AcquireInitialTokenRequest {
3334
* requests against one resource do not result in throttling for requests against other, unrelated resources.
3435
*/
3536
String scope();
37+
38+
/**
39+
* Creates a new {@link AcquireInitialTokenRequest} instance with the given scope.
40+
*/
41+
static AcquireInitialTokenRequest create(String scope) {
42+
return AcquireInitialTokenRequestImpl.create(scope);
43+
}
3644
}

core/retries-api/src/main/java/software/amazon/awssdk/retries/api/AcquireInitialTokenResponse.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
import java.time.Duration;
1919
import software.amazon.awssdk.annotations.SdkPublicApi;
2020
import software.amazon.awssdk.annotations.ThreadSafe;
21+
import software.amazon.awssdk.retries.api.internal.AcquireInitialTokenResponseImpl;
2122

2223
/**
2324
* Encapsulates the response from the {@link RetryStrategy} to the request to start the attempts to be executed.
@@ -35,4 +36,11 @@ public interface AcquireInitialTokenResponse {
3536
* The amount of time to wait before performing the first attempt.
3637
*/
3738
Duration delay();
39+
40+
/**
41+
* Creates a new {@link AcquireInitialTokenRequest} instance with the given scope.
42+
*/
43+
static AcquireInitialTokenResponse create(RetryToken token, Duration delay) {
44+
return AcquireInitialTokenResponseImpl.create(token, delay);
45+
}
3846
}

core/retries-api/src/main/java/software/amazon/awssdk/retries/api/RecordSuccessRequest.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717

1818
import software.amazon.awssdk.annotations.SdkPublicApi;
1919
import software.amazon.awssdk.annotations.ThreadSafe;
20+
import software.amazon.awssdk.retries.api.internal.RecordSuccessRequestImpl;
2021

2122
/**
2223
* Request that the calling code makes to the {@link RetryStrategy} using
@@ -30,4 +31,12 @@ public interface RecordSuccessRequest {
3031
* {@link RetryStrategy#refreshRetryToken} call.
3132
*/
3233
RetryToken token();
34+
35+
/**
36+
* Creates a new {@link RecordSuccessRequest} instance with the given token.
37+
*/
38+
static RecordSuccessRequest create(RetryToken token) {
39+
return RecordSuccessRequestImpl.create(token);
40+
}
41+
3342
}

core/retries-api/src/main/java/software/amazon/awssdk/retries/api/RecordSuccessResponse.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717

1818
import software.amazon.awssdk.annotations.SdkPublicApi;
1919
import software.amazon.awssdk.annotations.ThreadSafe;
20+
import software.amazon.awssdk.retries.api.internal.RecordSuccessResponseImpl;
2021

2122
/**
2223
* Response given to the calling code by the {@link RetryStrategy} after calling
@@ -30,4 +31,12 @@ public interface RecordSuccessResponse {
3031
* {@link RetryStrategy#refreshRetryToken} call.
3132
*/
3233
RetryToken token();
34+
35+
/**
36+
* Creates a new {@link RecordSuccessResponseImpl} with the given token.
37+
*/
38+
static RecordSuccessResponse create(RetryToken token) {
39+
return RecordSuccessResponseImpl.create(token);
40+
}
41+
3342
}

core/retries-api/src/main/java/software/amazon/awssdk/retries/api/RefreshRetryTokenRequest.java

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,9 @@
1919
import java.util.Optional;
2020
import software.amazon.awssdk.annotations.SdkPublicApi;
2121
import software.amazon.awssdk.annotations.ThreadSafe;
22+
import software.amazon.awssdk.retries.api.internal.RefreshRetryTokenRequestImpl;
23+
import software.amazon.awssdk.utils.builder.CopyableBuilder;
24+
import software.amazon.awssdk.utils.builder.ToCopyableBuilder;
2225

2326
/**
2427
* Request that the calling code makes to the {@link RetryStrategy} using
@@ -27,7 +30,7 @@
2730
*/
2831
@SdkPublicApi
2932
@ThreadSafe
30-
public interface RefreshRetryTokenRequest {
33+
public interface RefreshRetryTokenRequest extends ToCopyableBuilder<RefreshRetryTokenRequest.Builder, RefreshRetryTokenRequest> {
3134
/**
3235
* A {@link RetryToken} acquired a previous {@link RetryStrategy#acquireInitialToken} or
3336
* {@link RetryStrategy#refreshRetryToken} call.
@@ -44,4 +47,33 @@ public interface RefreshRetryTokenRequest {
4447
* The cause of the last attempt failure.
4548
*/
4649
Throwable failure();
50+
51+
/**
52+
* Returns a new builder to configure the {@link RefreshRetryTokenRequest} instance.
53+
*/
54+
static Builder builder() {
55+
return RefreshRetryTokenRequestImpl.builder();
56+
}
57+
58+
interface Builder extends CopyableBuilder<Builder, RefreshRetryTokenRequest> {
59+
/**
60+
* Configures the {@link RetryToken} to be refreshed.
61+
*/
62+
Builder token(RetryToken token);
63+
64+
/**
65+
* Configures the suggested delay to used when refreshing the token.
66+
*/
67+
Builder suggestedDelay(Duration duration);
68+
69+
/**
70+
* Configures the latest caught exception.
71+
*/
72+
Builder failure(Throwable throwable);
73+
74+
/**
75+
* Builds and returns a new instance of {@linke RefreshRetryTokenRequest}.
76+
*/
77+
RefreshRetryTokenRequest build();
78+
}
4779
}

core/retries-api/src/main/java/software/amazon/awssdk/retries/api/RefreshRetryTokenResponse.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
import java.time.Duration;
1919
import software.amazon.awssdk.annotations.SdkPublicApi;
2020
import software.amazon.awssdk.annotations.ThreadSafe;
21+
import software.amazon.awssdk.retries.api.internal.RefreshRetryTokenResponseImpl;
2122

2223
/**
2324
* Response from the {@link RetryStrategy} after calling {@link RetryStrategy#refreshRetryToken(RefreshRetryTokenRequest)}.
@@ -35,4 +36,11 @@ public interface RefreshRetryTokenResponse {
3536
* The amount of time to wait before performing the next attempt.
3637
*/
3738
Duration delay();
39+
40+
/**
41+
* Creates a new {@link RefreshRetryTokenResponse} with the given token and delay.
42+
*/
43+
static RefreshRetryTokenResponse create(RetryToken token, Duration delay) {
44+
return RefreshRetryTokenResponseImpl.create(token, delay);
45+
}
3846
}

core/retries-api/src/main/java/software/amazon/awssdk/retries/api/RetryStrategy.java

Lines changed: 18 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,10 @@
4141
*/
4242
@ThreadSafe
4343
@SdkPublicApi
44-
public interface RetryStrategy extends ToCopyableBuilder<RetryStrategy.Builder, RetryStrategy> {
44+
public interface RetryStrategy<
45+
B extends CopyableBuilder<B, T> & RetryStrategy.Builder<B, T>,
46+
T extends ToCopyableBuilder<B, T> & RetryStrategy<B, T>>
47+
extends ToCopyableBuilder<B, T> {
4548
/**
4649
* Invoked before the first request attempt.
4750
*
@@ -86,36 +89,39 @@ public interface RetryStrategy extends ToCopyableBuilder<RetryStrategy.Builder,
8689
* <p>This is useful for modifying the strategy's behavior, like conditions or max retries.
8790
*/
8891
@Override
89-
Builder toBuilder();
92+
B toBuilder();
9093

9194
/**
9295
* Builder to create immutable instances of {@link RetryStrategy}.
9396
*/
94-
interface Builder extends CopyableBuilder<Builder, RetryStrategy> {
97+
interface Builder<
98+
B extends Builder<B, T> & CopyableBuilder<B, T>,
99+
T extends ToCopyableBuilder<B, T> & RetryStrategy<B, T>>
100+
extends CopyableBuilder<B, T> {
95101
/**
96102
* Configure the strategy to retry when the provided predicate returns true, given a failure exception.
97103
*/
98-
Builder retryOnException(Predicate<Throwable> shouldRetry);
104+
B retryOnException(Predicate<Throwable> shouldRetry);
99105

100106
/**
101107
* Configure the strategy to retry when a failure exception class is equal to the provided class.
102108
*/
103-
default Builder retryOnException(Class<? extends Throwable> throwable) {
109+
default B retryOnException(Class<? extends Throwable> throwable) {
104110
return retryOnException(t -> t.getClass() == throwable);
105111
}
106112

107113
/**
108114
* Configure the strategy to retry when a failure exception class is an instance of the provided class (includes
109115
* subtypes).
110116
*/
111-
default Builder retryOnExceptionInstanceOf(Class<? extends Throwable> throwable) {
117+
default B retryOnExceptionInstanceOf(Class<? extends Throwable> throwable) {
112118
return retryOnException(t -> throwable.isAssignableFrom(t.getClass()));
113119
}
114120

115121
/**
116122
* Configure the strategy to retry when a failure exception or one of its cause classes is equal to the provided class.
117123
*/
118-
default Builder retryOnExceptionOrCause(Class<? extends Throwable> throwable) {
124+
default B retryOnExceptionOrCause(Class<? extends Throwable> throwable) {
119125
return retryOnException(t -> {
120126
if (t.getClass() == throwable) {
121127
return true;
@@ -135,7 +141,7 @@ default Builder retryOnExceptionOrCause(Class<? extends Throwable> throwable) {
135141
* Configure the strategy to retry when a failure exception or one of its cause classes is an instance of the provided
136142
* class (includes subtypes).
137143
*/
138-
default Builder retryOnExceptionOrCauseInstanceOf(Class<? extends Throwable> throwable) {
144+
default B retryOnExceptionOrCauseInstanceOf(Class<? extends Throwable> throwable) {
139145
return retryOnException(t -> {
140146
if (throwable.isAssignableFrom(t.getClass())) {
141147
return true;
@@ -155,7 +161,7 @@ default Builder retryOnExceptionOrCauseInstanceOf(Class<? extends Throwable> thr
155161
* Configure the strategy to retry the root cause of a failure (the final cause) a failure exception is equal to the
156162
* provided class.
157163
*/
158-
default Builder retryOnRootCause(Class<? extends Throwable> throwable) {
164+
default B retryOnRootCause(Class<? extends Throwable> throwable) {
159165
return retryOnException(t -> {
160166
boolean shouldRetry = false;
161167
Throwable cause = t.getCause();
@@ -171,7 +177,7 @@ default Builder retryOnRootCause(Class<? extends Throwable> throwable) {
171177
* Configure the strategy to retry the root cause of a failure (the final cause) a failure exception is an instance of to
172178
* the provided class (includes subtypes).
173179
*/
174-
default Builder retryOnRootCauseInstanceOf(Class<? extends Throwable> throwable) {
180+
default B retryOnRootCauseInstanceOf(Class<? extends Throwable> throwable) {
175181
return retryOnException(t -> {
176182
boolean shouldRetry = false;
177183
Throwable cause = t.getCause();
@@ -191,17 +197,12 @@ default Builder retryOnRootCauseInstanceOf(Class<? extends Throwable> throwable)
191197
*
192198
* <p>The default value for the standard and adaptive retry strategies is 3.
193199
*/
194-
Builder maxAttempts(int maxAttempts);
195-
196-
/**
197-
* Configure the predicate to allow the strategy categorize a Throwable as throttling exception.
198-
*/
199-
Builder treatAsThrottling(Predicate<Throwable> treatAsThrottling);
200+
B maxAttempts(int maxAttempts);
200201

201202
/**
202203
* Build a new {@link RetryStrategy} with the current configuration on this builder.
203204
*/
204205
@Override
205-
RetryStrategy build();
206+
T build();
206207
}
207208
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
/*
2+
* Copyright 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+
16+
package software.amazon.awssdk.retries.api.internal;
17+
18+
import software.amazon.awssdk.annotations.SdkInternalApi;
19+
import software.amazon.awssdk.retries.api.AcquireInitialTokenRequest;
20+
import software.amazon.awssdk.utils.Validate;
21+
22+
/**
23+
* Implementation of the {@link AcquireInitialTokenRequest} interface.
24+
*/
25+
@SdkInternalApi
26+
public final class AcquireInitialTokenRequestImpl implements AcquireInitialTokenRequest {
27+
28+
private final String scope;
29+
30+
private AcquireInitialTokenRequestImpl(String scope) {
31+
this.scope = Validate.paramNotNull(scope, "scope");
32+
}
33+
34+
@Override
35+
public String scope() {
36+
return scope;
37+
}
38+
39+
/**
40+
* Creates a new {@link AcquireInitialTokenRequestImpl} instance with the given scope.
41+
*/
42+
public static AcquireInitialTokenRequest create(String scope) {
43+
return new AcquireInitialTokenRequestImpl(scope);
44+
}
45+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
/*
2+
* Copyright 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+
16+
package software.amazon.awssdk.retries.api.internal;
17+
18+
import java.time.Duration;
19+
import software.amazon.awssdk.annotations.SdkInternalApi;
20+
import software.amazon.awssdk.retries.api.AcquireInitialTokenResponse;
21+
import software.amazon.awssdk.retries.api.RetryToken;
22+
import software.amazon.awssdk.utils.Validate;
23+
24+
/**
25+
* Implementation of the {@link AcquireInitialTokenResponse} interface.
26+
*/
27+
@SdkInternalApi
28+
public final class AcquireInitialTokenResponseImpl implements AcquireInitialTokenResponse {
29+
private final RetryToken token;
30+
private final Duration delay;
31+
32+
private AcquireInitialTokenResponseImpl(RetryToken token, Duration delay) {
33+
this.token = Validate.paramNotNull(token, "token");
34+
this.delay = Validate.paramNotNull(delay, "delay");
35+
}
36+
37+
@Override
38+
public RetryToken token() {
39+
return token;
40+
}
41+
42+
@Override
43+
public Duration delay() {
44+
return delay;
45+
}
46+
47+
/**
48+
* Creates a new {@link AcquireInitialTokenResponseImpl} instance with the given token and suggested delay values.
49+
*/
50+
public static AcquireInitialTokenResponse create(RetryToken token, Duration delay) {
51+
return new AcquireInitialTokenResponseImpl(token, delay);
52+
}
53+
}

0 commit comments

Comments
 (0)