Skip to content

Commit c78ad97

Browse files
committed
Update DDB retry policy with v2.1 constants
In 2.1: - base delay : 25ms (existing) - max attempts: 4 (down from 9)
1 parent 270414e commit c78ad97

4 files changed

Lines changed: 79 additions & 17 deletions

File tree

core/retries/src/test/java/software/amazon/awssdk/retries/StandardRetryStrategyV21ConstantsTest.java

Lines changed: 33 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
import static org.assertj.core.api.Assertions.assertThat;
1919

2020
import java.time.Duration;
21+
import java.util.function.Supplier;
2122
import org.junit.jupiter.api.Test;
2223
import software.amazon.awssdk.retries.api.AcquireInitialTokenResponse;
2324
import software.amazon.awssdk.retries.api.BackoffStrategy;
@@ -82,24 +83,33 @@ void v20_throttlingRetry_deducts5Tokens() {
8283

8384
@Test
8485
void v21Enabled_backoffUses50msBaseDelay() {
85-
RetryStrategy strategy = StandardRetryStrategy.builder(true)
86-
.retryOnException(t -> true)
87-
.build();
8886

89-
RefreshRetryTokenResponse response = refreshToken(strategy, new RuntimeException("err"));
90-
// First retry delay should be in [0, 50ms] (jittered)
91-
assertThat(response.delay()).isBetween(Duration.ZERO, Duration.ofMillis(50));
87+
Supplier<RetryStrategy> stratSupplier = () -> StandardRetryStrategy.builder(true)
88+
.retryOnException(t -> true)
89+
.build();
90+
91+
probabilisticAssertDelayBetween(stratSupplier, new RuntimeException("err"), Duration.ZERO, Duration.ofMillis(50));
92+
}
93+
94+
@Test
95+
void v21Enabled_throttlingBackoffUses1000msBaseDelay() {
96+
97+
Supplier<RetryStrategy> stratSupplier = () -> StandardRetryStrategy.builder(true)
98+
.retryOnException(t -> true)
99+
.treatAsThrottling(t -> true)
100+
.build();
101+
102+
probabilisticAssertDelayBetween(stratSupplier, new RuntimeException("err"), Duration.ZERO, Duration.ofMillis(1000));
92103
}
93104

94105
@Test
95106
void v20_backoffUses100msBaseDelay() {
96-
RetryStrategy strategy = StandardRetryStrategy.builder(false)
97-
.retryOnException(t -> true)
98-
.build();
107+
Supplier<RetryStrategy> stratSupplier = () -> StandardRetryStrategy.builder(false)
108+
.retryOnException(t -> true)
109+
.build();
110+
111+
probabilisticAssertDelayBetween(stratSupplier, new RuntimeException("err"), Duration.ZERO, Duration.ofMillis(100));
99112

100-
RefreshRetryTokenResponse response = refreshToken(strategy, new RuntimeException("err"));
101-
// First retry delay should be in [0, 100ms] (jittered)
102-
assertThat(response.delay()).isBetween(Duration.ZERO, Duration.ofMillis(100));
103113
}
104114

105115
@Test
@@ -135,4 +145,15 @@ private RefreshRetryTokenResponse refreshToken(RetryStrategy strategy, Exception
135145
return strategy.refreshRetryToken(
136146
RefreshRetryTokenRequest.builder().token(initial.token()).failure(failure).build());
137147
}
148+
149+
// Backoffs are jittered, so verify it by testing it many times
150+
private void probabilisticAssertDelayBetween(Supplier<RetryStrategy> strategy,
151+
Exception failure,
152+
Duration min,
153+
Duration max) {
154+
for (int i = 0; i < 128; ++i) {
155+
RefreshRetryTokenResponse response = refreshToken(strategy.get(), failure);
156+
assertThat(response.delay()).isBetween(min, max);
157+
}
158+
}
138159
}

services/dynamodb/pom.xml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,5 +78,11 @@
7878
<artifactId>http-auth-aws</artifactId>
7979
<version>${awsjavasdk.version}</version>
8080
</dependency>
81+
<dependency>
82+
<groupId>software.amazon.awssdk</groupId>
83+
<artifactId>retries</artifactId>
84+
<version>${awsjavasdk.version}</version>
85+
<scope>test</scope>
86+
</dependency>
8187
</dependencies>
8288
</project>

services/dynamodb/src/main/java/software/amazon/awssdk/services/dynamodb/DynamoDbRetryPolicy.java

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
import software.amazon.awssdk.core.client.config.SdkClientOption;
2626
import software.amazon.awssdk.core.internal.retry.RetryPolicyAdapter;
2727
import software.amazon.awssdk.core.internal.retry.SdkDefaultRetrySetting;
28+
import software.amazon.awssdk.core.retry.NewRetries2026Resolver;
2829
import software.amazon.awssdk.core.retry.RetryMode;
2930
import software.amazon.awssdk.core.retry.RetryPolicy;
3031
import software.amazon.awssdk.core.retry.backoff.BackoffStrategy;
@@ -41,12 +42,17 @@ final class DynamoDbRetryPolicy {
4142
/**
4243
* Default max retry count for DynamoDB client, regardless of retry mode.
4344
**/
44-
private static final int MAX_ERROR_RETRY = 8;
45+
private static final int MAX_ERROR_RETRY_V20 = 8;
4546

4647
/**
4748
* Default attempts count for DynamoDB client, regardless of retry mode.
4849
**/
49-
private static final int MAX_ATTEMPTS = MAX_ERROR_RETRY + 1;
50+
private static final int MAX_ATTEMPTS_V20 = MAX_ERROR_RETRY_V20 + 1;
51+
52+
/**
53+
* Default attempts count for DynamoDB client, regardless of retry mode. (v2.1)
54+
**/
55+
private static final int MAX_ATTEMPTS_V21 = 4;
5056

5157
/**
5258
* Default base sleep time for DynamoDB, regardless of retry mode.
@@ -95,9 +101,12 @@ public static RetryStrategy resolveRetryStrategy(SdkClientConfiguration config)
95101
.build();
96102
}
97103

98-
return AwsRetryStrategy.forRetryMode(retryMode)
104+
boolean newRetries2026Enabled = isNewRetries2026Enabled(config);
105+
int maxAttempts = newRetries2026Enabled ? MAX_ATTEMPTS_V21 : MAX_ATTEMPTS_V20;
106+
107+
return AwsRetryStrategy.forRetryMode(retryMode, newRetries2026Enabled)
99108
.toBuilder()
100-
.maxAttempts(MAX_ATTEMPTS)
109+
.maxAttempts(maxAttempts)
101110
.backoffStrategy(exponentialDelay(BASE_DELAY, SdkDefaultRetrySetting.MAX_BACKOFF))
102111
.build();
103112
}
@@ -106,7 +115,7 @@ private static RetryPolicy retryPolicyFor(RetryMode retryMode) {
106115
return AwsRetryPolicy.forRetryMode(retryMode)
107116
.toBuilder()
108117
.additionalRetryConditionsAllowed(false)
109-
.numRetries(MAX_ERROR_RETRY)
118+
.numRetries(MAX_ERROR_RETRY_V20)
110119
.backoffStrategy(BACKOFF_STRATEGY)
111120
.build();
112121
}
@@ -116,6 +125,12 @@ private static RetryMode resolveRetryMode(SdkClientConfiguration config) {
116125
.profileFile(config.option(SdkClientOption.PROFILE_FILE_SUPPLIER))
117126
.profileName(config.option(SdkClientOption.PROFILE_NAME))
118127
.defaultRetryMode(config.option(SdkClientOption.DEFAULT_RETRY_MODE))
128+
.defaultNewRetries2026(config.option(SdkClientOption.DEFAULT_NEW_RETRIES_2026))
119129
.resolve();
120130
}
131+
132+
private static boolean isNewRetries2026Enabled(SdkClientConfiguration config) {
133+
Boolean defaultNewRetries2026 = config.option(SdkClientOption.DEFAULT_NEW_RETRIES_2026);
134+
return new NewRetries2026Resolver().defaultNewRetries2026(defaultNewRetries2026).resolve();
135+
}
121136
}

services/dynamodb/src/test/java/software/amazon/awssdk/services/dynamodb/DynamoDbRetryPolicyTest.java

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,16 @@
55
import org.junit.jupiter.api.AfterEach;
66
import org.junit.jupiter.api.BeforeEach;
77
import org.junit.jupiter.api.Test;
8+
import org.junit.jupiter.params.ParameterizedTest;
9+
import org.junit.jupiter.params.provider.CsvSource;
810
import software.amazon.awssdk.core.SdkSystemSetting;
911
import software.amazon.awssdk.core.client.config.SdkClientConfiguration;
1012
import software.amazon.awssdk.core.client.config.SdkClientOption;
1113
import software.amazon.awssdk.core.internal.retry.SdkDefaultRetryStrategy;
1214
import software.amazon.awssdk.core.retry.RetryMode;
1315
import software.amazon.awssdk.profiles.ProfileFile;
16+
import software.amazon.awssdk.retries.LegacyRetryStrategy;
17+
import software.amazon.awssdk.retries.StandardRetryStrategy;
1418
import software.amazon.awssdk.retries.api.RetryStrategy;
1519
import software.amazon.awssdk.testutils.EnvironmentVariableHelper;
1620
import software.amazon.awssdk.utils.StringInputStream;
@@ -126,4 +130,20 @@ void resolve_retryModeNotSetWithEnvNorSupplier_resolvesFromSdkDefault() {
126130
assertThat(retryMode).isEqualTo(RetryMode.LEGACY);
127131
}
128132

133+
@ParameterizedTest(name = "V2.1 retries = {0}, max attempts = {1}")
134+
@CsvSource({
135+
"false,9",
136+
"true,4"
137+
})
138+
void resolve_maxAttemptsAndStrategyCompliantWithRetriesVersion(boolean retries21, int expectedMaxAttempts) {
139+
SdkClientConfiguration cfg = SdkClientConfiguration.builder()
140+
.option(SdkClientOption.DEFAULT_NEW_RETRIES_2026, retries21)
141+
.build();
142+
RetryStrategy strategy = DynamoDbRetryPolicy.resolveRetryStrategy(cfg);
143+
144+
Class<?> expectedStrategy = retries21 ? StandardRetryStrategy.class : LegacyRetryStrategy.class;
145+
146+
assertThat(strategy).isInstanceOf(expectedStrategy);
147+
assertThat(strategy.maxAttempts()).isEqualTo(expectedMaxAttempts);
148+
}
129149
}

0 commit comments

Comments
 (0)