From c7a08318f6268a2dd914c7769a4cca93ddef0624 Mon Sep 17 00:00:00 2001 From: Olivier Lepage-Applin Date: Fri, 18 Oct 2024 16:01:53 -0400 Subject: [PATCH 1/7] Add SDK and AWS defaults retry predicate when retry strategy contains user specified predicates. Add a configuration to opt-out, to have the retry strategy use only the use user-provided predicates. --- core/aws-core/pom.xml | 5 + .../builder/AwsDefaultClientBuilder.java | 69 ++++++------ .../awscore/retry/AwsRetryStrategy.java | 19 +++- .../builder/DefaultAwsClientBuilderTest.java | 101 ++++++++++++++++-- .../awssdk/retries/api/RetryStrategy.java | 22 +++- .../retries/internal/BaseRetryStrategy.java | 55 +++++++++- .../DefaultAdaptiveRetryStrategy.java | 7 ++ .../internal/DefaultLegacyRetryStrategy.java | 6 ++ .../DefaultStandardRetryStrategy.java | 6 ++ .../retry/SdkDefaultRetryStrategy.java | 21 +++- 10 files changed, 266 insertions(+), 45 deletions(-) diff --git a/core/aws-core/pom.xml b/core/aws-core/pom.xml index 9b0856c6f5bd..f93e310dbca3 100644 --- a/core/aws-core/pom.xml +++ b/core/aws-core/pom.xml @@ -165,6 +165,11 @@ mockito-core test + + org.mockito + mockito-junit-jupiter + test + nl.jqno.equalsverifier equalsverifier diff --git a/core/aws-core/src/main/java/software/amazon/awssdk/awscore/client/builder/AwsDefaultClientBuilder.java b/core/aws-core/src/main/java/software/amazon/awssdk/awscore/client/builder/AwsDefaultClientBuilder.java index a00d144dc147..e4d8b31ce614 100644 --- a/core/aws-core/src/main/java/software/amazon/awssdk/awscore/client/builder/AwsDefaultClientBuilder.java +++ b/core/aws-core/src/main/java/software/amazon/awssdk/awscore/client/builder/AwsDefaultClientBuilder.java @@ -24,6 +24,7 @@ import java.util.Arrays; import java.util.List; import java.util.Optional; +import java.util.function.Consumer; import java.util.function.Supplier; import software.amazon.awssdk.annotations.SdkProtectedApi; import software.amazon.awssdk.annotations.SdkTestInternalApi; @@ -76,12 +77,10 @@ /** * An SDK-internal implementation of the methods in {@link AwsClientBuilder}, {@link AwsAsyncClientBuilder} and * {@link AwsSyncClientBuilder}. This implements all methods required by those interfaces, allowing service-specific builders to - * just - * implement the configuration they wish to add. + * just implement the configuration they wish to add. * *

By implementing both the sync and async interface's methods, service-specific builders can share code between their sync - * and - * async variants without needing one to extend the other. Note: This only defines the methods in the sync and async builder + * and async variants without needing one to extend the other. Note: This only defines the methods in the sync and async builder * interfaces. It does not implement the interfaces themselves. This is because the sync and async client builder interfaces both * require a type-constrained parameter for use in fluent chaining, and a generic type parameter conflict is introduced into the * class hierarchy by this interface extending the builder interfaces themselves.

@@ -89,7 +88,7 @@ *

Like all {@link AwsClientBuilder}s, this class is not thread safe.

* * @param The type of builder, for chaining. - * @param The type of client generated by this builder. + * @param The type of client generated by this builder. */ @SdkProtectedApi public abstract class AwsDefaultClientBuilder, ClientT> @@ -228,8 +227,8 @@ protected final SdkClientConfiguration setOverrides(SdkClientConfiguration confi } /** - * Check {@link SdkInternalTestAdvancedClientOption#ENDPOINT_OVERRIDDEN_OVERRIDE} to see if we should override the - * value returned by {@link SdkClientOption#CLIENT_ENDPOINT_PROVIDER}'s isEndpointOverridden. + * Check {@link SdkInternalTestAdvancedClientOption#ENDPOINT_OVERRIDDEN_OVERRIDE} to see if we should override the value + * returned by {@link SdkClientOption#CLIENT_ENDPOINT_PROVIDER}'s isEndpointOverridden. */ private void checkEndpointOverriddenOverride(SdkClientConfiguration configuration, SdkClientConfiguration.Builder builder) { Optional endpointOverriddenOverride = @@ -339,16 +338,16 @@ private ClientEndpointProvider resolveClientEndpointProvider(LazyValueSource con } /** - * Resolve the client endpoint. This code is only needed by old SDK client versions. Newer SDK client versions - * resolve this information from the client endpoint provider. + * Resolve the client endpoint. This code is only needed by old SDK client versions. Newer SDK client versions resolve this + * information from the client endpoint provider. */ private URI resolveEndpoint(LazyValueSource config) { return config.get(SdkClientOption.CLIENT_ENDPOINT_PROVIDER).clientEndpoint(); } /** - * Resolve whether the endpoint was overridden by the customer. This code is only needed by old SDK client - * versions. Newer SDK client versions resolve this information from the client endpoint provider. + * Resolve whether the endpoint was overridden by the customer. This code is only needed by old SDK client versions. Newer SDK + * client versions resolve this information from the client endpoint provider. */ private boolean resolveEndpointOverridden(LazyValueSource config) { return config.get(SdkClientOption.CLIENT_ENDPOINT_PROVIDER).isEndpointOverridden(); @@ -423,28 +422,32 @@ private void configureRetryPolicy(SdkClientConfiguration.Builder config) { private void configureRetryStrategy(SdkClientConfiguration.Builder config) { RetryStrategy strategy = config.option(SdkClientOption.RETRY_STRATEGY); - if (strategy != null) { - // TODO(10/09/24) This is a temporal workaround and not a long term solution. It will fail to add the SDK and AWS - // defaults if the users add one or more if their own retry predicates. A long term fix is needed that can - // "remember" which defaults have been already applied, e.g., - // if (strategy.shouldAddDefaults("aws")) { - // strategy = strategy.toBuilder() - // .applyMutation(AwsRetryStrategy::applyDefaults) - // .markDefaultsAdded("aws") - // .build(); - // } - if (strategy.maxAttempts() > 1 - && (strategy instanceof BaseRetryStrategy) - && !((BaseRetryStrategy) strategy).hasRetryPredicates() - ) { - RetryStrategy.Builder builder = strategy.toBuilder(); - SdkDefaultRetryStrategy.configureStrategy(builder); - AwsRetryStrategy.configureStrategy(builder); - config.option(SdkClientOption.RETRY_STRATEGY, builder.build()); - } + if (strategy == null) { + config.lazyOption(SdkClientOption.RETRY_STRATEGY, this::resolveAwsRetryStrategy); return; } - config.lazyOption(SdkClientOption.RETRY_STRATEGY, this::resolveAwsRetryStrategy); + + if (!strategy.useClientDefaults()) { + return; + } + + if (!(strategy instanceof BaseRetryStrategy)) { + return; + } + + BaseRetryStrategy baseRetryStrategy = (BaseRetryStrategy) strategy; + RetryStrategy.Builder baseRetryStrategyBuilder = baseRetryStrategy.toBuilder(); + + if (baseRetryStrategy.shouldAddDefaults(AwsRetryStrategy.DEFAULTS_NAME)) { + baseRetryStrategyBuilder.applyMutation(AwsRetryStrategy::applyDefault); + } + + if (baseRetryStrategy.shouldAddDefaults(SdkDefaultRetryStrategy.DEFAULTS_NAME)) { + baseRetryStrategyBuilder.applyMutation(SdkDefaultRetryStrategy::applyDefault); + } + + config.option(SdkClientOption.RETRY_STRATEGY, baseRetryStrategyBuilder.build()); + } private RetryStrategy resolveAwsRetryStrategy(LazyValueSource config) { @@ -536,8 +539,8 @@ public final void setDefaultsMode(DefaultsMode defaultsMode) { /** * If the region is a FIPS pseudo region (contains "fips"), this method returns a pair of values, the left side being the - * region with the "fips" string removed, and the right being {@code true}. Otherwise, the region is returned - * unchanged, and the right will be empty. + * region with the "fips" string removed, and the right being {@code true}. Otherwise, the region is returned unchanged, and + * the right will be empty. */ private static Pair> transformFipsPseudoRegionIfNecessary(Region region) { String id = region.id(); diff --git a/core/aws-core/src/main/java/software/amazon/awssdk/awscore/retry/AwsRetryStrategy.java b/core/aws-core/src/main/java/software/amazon/awssdk/awscore/retry/AwsRetryStrategy.java index bef57e64f301..3bf54b6bfc5b 100644 --- a/core/aws-core/src/main/java/software/amazon/awssdk/awscore/retry/AwsRetryStrategy.java +++ b/core/aws-core/src/main/java/software/amazon/awssdk/awscore/retry/AwsRetryStrategy.java @@ -26,6 +26,7 @@ import software.amazon.awssdk.retries.LegacyRetryStrategy; import software.amazon.awssdk.retries.StandardRetryStrategy; import software.amazon.awssdk.retries.api.RetryStrategy; +import software.amazon.awssdk.retries.internal.BaseRetryStrategy; /** * Retry strategies used by clients when communicating with AWS services. @@ -33,6 +34,8 @@ @SdkPublicApi public final class AwsRetryStrategy { + public static final String DEFAULTS_NAME = "aws"; + private AwsRetryStrategy() { } @@ -127,7 +130,9 @@ public static AdaptiveRetryStrategy adaptiveRetryStrategy() { * @return The given builder */ public static > T configure(T builder) { - return builder.retryOnException(AwsRetryStrategy::retryOnAwsRetryableErrors); + builder.retryOnException(AwsRetryStrategy::retryOnAwsRetryableErrors); + markDefaultsAdded(builder); + return builder; } /** @@ -162,4 +167,16 @@ private static RetryStrategy legacyAdaptiveRetryStrategy() { .build(); } + public static void applyDefault(RetryStrategy.Builder builder) { + configureStrategy(builder); + markDefaultsAdded(builder); + } + + private static void markDefaultsAdded(RetryStrategy.Builder builder) { + if (builder instanceof BaseRetryStrategy.Builder) { + BaseRetryStrategy.Builder b = (BaseRetryStrategy.Builder) builder; + b.markDefaultAdded(DEFAULTS_NAME); + } + } + } diff --git a/core/aws-core/src/test/java/software/amazon/awssdk/awscore/client/builder/DefaultAwsClientBuilderTest.java b/core/aws-core/src/test/java/software/amazon/awssdk/awscore/client/builder/DefaultAwsClientBuilderTest.java index ca3061cca171..2b29e017ebd2 100644 --- a/core/aws-core/src/test/java/software/amazon/awssdk/awscore/client/builder/DefaultAwsClientBuilderTest.java +++ b/core/aws-core/src/test/java/software/amazon/awssdk/awscore/client/builder/DefaultAwsClientBuilderTest.java @@ -35,29 +35,42 @@ import java.time.Duration; import java.util.Arrays; import java.util.Optional; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; +import java.util.stream.Stream; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; +import org.mockito.junit.MockitoJUnit; import software.amazon.awssdk.auth.credentials.AnonymousCredentialsProvider; import software.amazon.awssdk.auth.signer.Aws4Signer; import software.amazon.awssdk.awscore.client.config.AwsClientOption; import software.amazon.awssdk.awscore.internal.defaultsmode.AutoDefaultsModeDiscovery; +import software.amazon.awssdk.awscore.retry.AwsRetryStrategy; import software.amazon.awssdk.core.client.config.ClientOverrideConfiguration; import software.amazon.awssdk.core.client.config.SdkClientConfiguration; import software.amazon.awssdk.core.client.config.SdkClientOption; +import software.amazon.awssdk.core.internal.retry.SdkDefaultRetryStrategy; import software.amazon.awssdk.core.signer.Signer; import software.amazon.awssdk.http.SdkHttpClient; import software.amazon.awssdk.http.SdkHttpConfigurationOption; import software.amazon.awssdk.http.async.SdkAsyncHttpClient; import software.amazon.awssdk.regions.Region; +import software.amazon.awssdk.retries.AdaptiveRetryStrategy; +import software.amazon.awssdk.retries.LegacyRetryStrategy; +import software.amazon.awssdk.retries.StandardRetryStrategy; +import software.amazon.awssdk.retries.api.BackoffStrategy; +import software.amazon.awssdk.retries.api.RetryStrategy; +import software.amazon.awssdk.retries.internal.BaseRetryStrategy; import software.amazon.awssdk.utils.AttributeMap; +import org.mockito.junit.jupiter.MockitoExtension; /** * Validate the functionality of the {@link AwsDefaultClientBuilder}. */ -@RunWith(MockitoJUnitRunner.class) +@ExtendWith(MockitoExtension.class) public class DefaultAwsClientBuilderTest { private static final AttributeMap MOCK_DEFAULTS = AttributeMap @@ -71,16 +84,16 @@ public class DefaultAwsClientBuilderTest { private static final Signer TEST_SIGNER = Aws4Signer.create(); private static final URI ENDPOINT = URI.create("https://example.com"); - @Mock + @Mock(lenient = true) private SdkHttpClient.Builder defaultHttpClientBuilder; - @Mock + @Mock(lenient = true) private SdkAsyncHttpClient.Builder defaultAsyncHttpClientFactory; @Mock private AutoDefaultsModeDiscovery autoModeDiscovery; - @Before + @BeforeEach public void setup() { when(defaultHttpClientBuilder.buildWithDefaults(any())).thenReturn(mock(SdkHttpClient.class)); when(defaultAsyncHttpClientFactory.buildWithDefaults(any())).thenReturn(mock(SdkAsyncHttpClient.class)); @@ -251,6 +264,75 @@ public void clientBuilderFieldsHaveBeanEquivalents() throws Exception { }); } + @ParameterizedTest(name = "{0} - expectedPredicateAmount: {2}") + @MethodSource("retryArguments") + public void retryStrategyConfiguration_shouldAddDefaultPredicatesWhenRequired( + String testDescription, RetryStrategy retryStrategy, int expectedPredicateAmount) { + TestClientBuilder builder = testClientBuilder() + .region(Region.US_EAST_1) + .overrideConfiguration(c -> c.retryStrategy(retryStrategy)); + TestClient client = builder.build(); + + ClientOverrideConfiguration conf = client.clientConfiguration.asOverrideConfiguration(); + assertThat(conf.retryStrategy()).isPresent(); + + RetryStrategy configuredRetryStrategy = conf.retryStrategy().get(); + BaseRetryStrategy baseRetryStrategy = (BaseRetryStrategy) configuredRetryStrategy; + assertThat(baseRetryStrategy.shouldAddDefaults(AwsRetryStrategy.DEFAULTS_NAME)).isFalse(); + assertThat(baseRetryStrategy.shouldAddDefaults(SdkDefaultRetryStrategy.DEFAULTS_NAME)).isFalse(); + assertThat(baseRetryStrategy.retryPredicates()).hasSize(expectedPredicateAmount); + } + + private static Stream retryArguments() { + return Stream.of( + Arguments.of("Standard - static method creation", + SdkDefaultRetryStrategy.standardRetryStrategy(), 9), + Arguments.of("Standard - builder with retryOnException", + StandardRetryStrategy.builder() + .retryOnException(TestException.class) + .backoffStrategy(BackoffStrategy.retryImmediately()) + .throttlingBackoffStrategy(BackoffStrategy.retryImmediately()) + .build(), 10), + Arguments.of("Standard - useClientDefaults=false", + StandardRetryStrategy.builder() + .retryOnException(TestException.class) + .backoffStrategy(BackoffStrategy.retryImmediately()) + .throttlingBackoffStrategy(BackoffStrategy.retryImmediately()) + .useClientDefaults(false) + .build(), 1), + Arguments.of("Adaptive - static method creation", + SdkDefaultRetryStrategy.adaptiveRetryStrategy(), 9), + Arguments.of("Adaptive - builder with retryOnException", + AdaptiveRetryStrategy.builder() + .retryOnException(TestException.class) + .backoffStrategy(BackoffStrategy.retryImmediately()) + .throttlingBackoffStrategy(BackoffStrategy.retryImmediately()) + .build(), 10), + Arguments.of("Adaptive - useClientDefaults=false", + AdaptiveRetryStrategy.builder() + .retryOnException(TestException.class) + .backoffStrategy(BackoffStrategy.retryImmediately()) + .throttlingBackoffStrategy(BackoffStrategy.retryImmediately()) + .useClientDefaults(false) + .build(), 1), + Arguments.of("Legacy - static method creation", + SdkDefaultRetryStrategy.legacyRetryStrategy(), 9), + Arguments.of("Legacy - builder with retryOnException", + LegacyRetryStrategy.builder() + .retryOnException(TestException.class) + .backoffStrategy(BackoffStrategy.retryImmediately()) + .throttlingBackoffStrategy(BackoffStrategy.retryImmediately()) + .build(), 10), + Arguments.of("Legacy - useClientDefaults=false", + LegacyRetryStrategy.builder() + .retryOnException(TestException.class) + .backoffStrategy(BackoffStrategy.retryImmediately()) + .throttlingBackoffStrategy(BackoffStrategy.retryImmediately()) + .useClientDefaults(false) + .build(), 1) + ); + } + private AwsClientBuilder testClientBuilder() { ClientOverrideConfiguration overrideConfig = ClientOverrideConfiguration.builder() @@ -354,4 +436,7 @@ protected AttributeMap serviceHttpConfig() { return MOCK_DEFAULTS; } } + + private static class TestException extends Throwable { + } } diff --git a/core/retries-spi/src/main/java/software/amazon/awssdk/retries/api/RetryStrategy.java b/core/retries-spi/src/main/java/software/amazon/awssdk/retries/api/RetryStrategy.java index b7d8a66e93ec..491bab172e65 100644 --- a/core/retries-spi/src/main/java/software/amazon/awssdk/retries/api/RetryStrategy.java +++ b/core/retries-spi/src/main/java/software/amazon/awssdk/retries/api/RetryStrategy.java @@ -18,6 +18,7 @@ import java.util.function.Predicate; import software.amazon.awssdk.annotations.SdkPublicApi; import software.amazon.awssdk.annotations.ThreadSafe; +import software.amazon.awssdk.utils.builder.SdkBuilder; /** * A strategy used by an SDK to determine when something should be retried. @@ -85,6 +86,15 @@ public interface RetryStrategy { */ int maxAttempts(); + /** + * Returns whether the retry strategy uses default retry predicates. + * + * @return true if this retry strategy should use the default retry predicates, false otherwise. + */ + default boolean useClientDefaults() { + return true; + } + /** * Create a new {@link Builder} with the current configuration. * @@ -97,7 +107,7 @@ public interface RetryStrategy { */ interface Builder< B extends Builder, - T extends RetryStrategy> { + T extends RetryStrategy> extends SdkBuilder { /** * Configure the strategy to retry when the provided predicate returns true, given a failure exception. */ @@ -218,6 +228,16 @@ default B retryOnRootCauseInstanceOf(Class throwable) { */ B treatAsThrottling(Predicate treatAsThrottling); + + /** + * Configure whether the default predicates should be used, or not. When set to false, only user-provided retry + * predicates will be considered to determine what should be retried or not. Setting this to false and providing + * no predicate will result in an empty retry strategy. + */ + default B useClientDefaults(boolean useClientDefaults) { + return (B) this; + } + /** * Build a new {@link RetryStrategy} with the current configuration on this builder. */ diff --git a/core/retries/src/main/java/software/amazon/awssdk/retries/internal/BaseRetryStrategy.java b/core/retries/src/main/java/software/amazon/awssdk/retries/internal/BaseRetryStrategy.java index 4d950dcae06a..3a25e4315b1f 100644 --- a/core/retries/src/main/java/software/amazon/awssdk/retries/internal/BaseRetryStrategy.java +++ b/core/retries/src/main/java/software/amazon/awssdk/retries/internal/BaseRetryStrategy.java @@ -17,10 +17,14 @@ import java.time.Duration; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; +import java.util.HashSet; import java.util.List; +import java.util.Set; import java.util.function.Predicate; import software.amazon.awssdk.annotations.SdkInternalApi; +import software.amazon.awssdk.annotations.SdkProtectedApi; import software.amazon.awssdk.retries.api.AcquireInitialTokenRequest; import software.amazon.awssdk.retries.api.AcquireInitialTokenResponse; import software.amazon.awssdk.retries.api.BackoffStrategy; @@ -36,8 +40,10 @@ import software.amazon.awssdk.retries.internal.circuitbreaker.ReleaseResponse; import software.amazon.awssdk.retries.internal.circuitbreaker.TokenBucket; import software.amazon.awssdk.retries.internal.circuitbreaker.TokenBucketStore; +import software.amazon.awssdk.utils.CollectionUtils; import software.amazon.awssdk.utils.Logger; import software.amazon.awssdk.utils.Validate; +import software.amazon.awssdk.utils.builder.SdkBuilder; /** * Generic class that implements that common logic for all the retries strategies with extension points for specific strategies to @@ -55,6 +61,8 @@ public abstract class BaseRetryStrategy implements RetryStrategy { protected final Predicate treatAsThrottling; protected final int exceptionCost; protected final TokenBucketStore tokenBucketStore; + protected final Set defaultsAdded; + protected final Boolean useClientDefaults; BaseRetryStrategy(Logger log, Builder builder) { this.log = log; @@ -66,6 +74,8 @@ public abstract class BaseRetryStrategy implements RetryStrategy { this.treatAsThrottling = Validate.paramNotNull(builder.treatAsThrottling, "treatAsThrottling"); this.exceptionCost = Validate.paramNotNull(builder.exceptionCost, "exceptionCost"); this.tokenBucketStore = Validate.paramNotNull(builder.tokenBucketStore, "tokenBucketStore"); + this.defaultsAdded = Validate.paramNotNull(builder.defaultsAdded, "defaultsAdded"); + this.useClientDefaults = builder.useClientDefaults == null || builder.useClientDefaults; } /** @@ -139,6 +149,10 @@ public int maxAttempts() { return maxAttempts; } + @Override + public boolean useClientDefaults() { + return useClientDefaults; + } /** * Computes the backoff before the first attempt, by default {@link Duration#ZERO}. Extending classes can override this method @@ -196,6 +210,10 @@ public final boolean hasRetryPredicates() { return !retryPredicates.isEmpty(); } + public List> retryPredicates() { + return retryPredicates; + } + private DefaultRetryToken refreshToken(RefreshRetryTokenRequest request, AcquireResponse acquireResponse) { DefaultRetryToken token = asDefaultRetryToken(request.token()); return token.toBuilder() @@ -352,7 +370,29 @@ static DefaultRetryToken asDefaultRetryToken(RetryToken token) { token.getClass().getName()); } - static class Builder { + @Override + public String toString() { + final StringBuilder sb = new StringBuilder("BaseRetryStrategy{"); + sb.append("retryPredicates=").append(retryPredicates); + sb.append(", maxAttempts=").append(maxAttempts); + sb.append(", circuitBreakerEnabled=").append(circuitBreakerEnabled); + sb.append(", backoffStrategy=").append(backoffStrategy); + sb.append(", throttlingBackoffStrategy=").append(throttlingBackoffStrategy); + sb.append(", treatAsThrottling=").append(treatAsThrottling); + sb.append(", exceptionCost=").append(exceptionCost); + sb.append(", tokenBucketStore=").append(tokenBucketStore); + sb.append(", defaultsAdded=").append(defaultsAdded); + sb.append(", useClientDefaults=").append(useClientDefaults); + sb.append('}'); + return sb.toString(); + } + + public boolean shouldAddDefaults(String defaultPredicateName) { + return useClientDefaults && !defaultsAdded.contains(defaultPredicateName); + } + + @SdkProtectedApi + public abstract static class Builder { private List> retryPredicates; private int maxAttempts; private Boolean circuitBreakerEnabled; @@ -361,9 +401,12 @@ static class Builder { private BackoffStrategy throttlingBackoffStrategy; private Predicate treatAsThrottling = throwable -> false; private TokenBucketStore tokenBucketStore; + protected Set defaultsAdded; + private Boolean useClientDefaults; Builder() { retryPredicates = new ArrayList<>(); + defaultsAdded = new HashSet<>(); } Builder(BaseRetryStrategy strategy) { @@ -375,6 +418,7 @@ static class Builder { this.throttlingBackoffStrategy = strategy.throttlingBackoffStrategy; this.treatAsThrottling = strategy.treatAsThrottling; this.tokenBucketStore = strategy.tokenBucketStore; + this.defaultsAdded = strategy.defaultsAdded; } void setRetryOnException(Predicate shouldRetry) { @@ -408,5 +452,14 @@ void setTreatAsThrottling(Predicate treatAsThrottling) { void setTokenBucketExceptionCost(int exceptionCost) { this.exceptionCost = exceptionCost; } + + void setUseClientDefaults(Boolean useClientDefaults) { + this.useClientDefaults = useClientDefaults; + } + + public void markDefaultAdded(String d) { + defaultsAdded.add(d); + } + } } diff --git a/core/retries/src/main/java/software/amazon/awssdk/retries/internal/DefaultAdaptiveRetryStrategy.java b/core/retries/src/main/java/software/amazon/awssdk/retries/internal/DefaultAdaptiveRetryStrategy.java index bd526b057e4e..19cb807341f0 100644 --- a/core/retries/src/main/java/software/amazon/awssdk/retries/internal/DefaultAdaptiveRetryStrategy.java +++ b/core/retries/src/main/java/software/amazon/awssdk/retries/internal/DefaultAdaptiveRetryStrategy.java @@ -22,6 +22,7 @@ import software.amazon.awssdk.retries.api.AcquireInitialTokenRequest; import software.amazon.awssdk.retries.api.BackoffStrategy; import software.amazon.awssdk.retries.api.RefreshRetryTokenRequest; +import software.amazon.awssdk.retries.api.RetryStrategy; import software.amazon.awssdk.retries.internal.circuitbreaker.TokenBucketStore; import software.amazon.awssdk.retries.internal.ratelimiter.RateLimiterTokenBucket; import software.amazon.awssdk.retries.internal.ratelimiter.RateLimiterTokenBucketStore; @@ -139,6 +140,12 @@ public Builder tokenBucketStore(TokenBucketStore tokenBucketStore) { return this; } + @Override + public Builder useClientDefaults(boolean useClientDefaults) { + setUseClientDefaults(useClientDefaults); + return this; + } + @Override public AdaptiveRetryStrategy build() { return new DefaultAdaptiveRetryStrategy(this); diff --git a/core/retries/src/main/java/software/amazon/awssdk/retries/internal/DefaultLegacyRetryStrategy.java b/core/retries/src/main/java/software/amazon/awssdk/retries/internal/DefaultLegacyRetryStrategy.java index 9ad358e4c8f5..23520a68c234 100644 --- a/core/retries/src/main/java/software/amazon/awssdk/retries/internal/DefaultLegacyRetryStrategy.java +++ b/core/retries/src/main/java/software/amazon/awssdk/retries/internal/DefaultLegacyRetryStrategy.java @@ -117,6 +117,12 @@ public Builder tokenBucketStore(TokenBucketStore tokenBucketStore) { return this; } + @Override + public Builder useClientDefaults(boolean useClientDefaults) { + setUseClientDefaults(useClientDefaults); + return this; + } + @Override public LegacyRetryStrategy build() { return new DefaultLegacyRetryStrategy(this); diff --git a/core/retries/src/main/java/software/amazon/awssdk/retries/internal/DefaultStandardRetryStrategy.java b/core/retries/src/main/java/software/amazon/awssdk/retries/internal/DefaultStandardRetryStrategy.java index ada7ba1efe3c..3a6a120fa398 100644 --- a/core/retries/src/main/java/software/amazon/awssdk/retries/internal/DefaultStandardRetryStrategy.java +++ b/core/retries/src/main/java/software/amazon/awssdk/retries/internal/DefaultStandardRetryStrategy.java @@ -95,6 +95,12 @@ public Builder tokenBucketStore(TokenBucketStore tokenBucketStore) { return this; } + @Override + public Builder useClientDefaults(boolean useClientDefaults) { + setUseClientDefaults(useClientDefaults); + return this; + } + @Override public StandardRetryStrategy build() { return new DefaultStandardRetryStrategy(this); diff --git a/core/sdk-core/src/main/java/software/amazon/awssdk/core/internal/retry/SdkDefaultRetryStrategy.java b/core/sdk-core/src/main/java/software/amazon/awssdk/core/internal/retry/SdkDefaultRetryStrategy.java index d5f1320f1af2..74d17e005d7c 100644 --- a/core/sdk-core/src/main/java/software/amazon/awssdk/core/internal/retry/SdkDefaultRetryStrategy.java +++ b/core/sdk-core/src/main/java/software/amazon/awssdk/core/internal/retry/SdkDefaultRetryStrategy.java @@ -26,7 +26,9 @@ import software.amazon.awssdk.retries.DefaultRetryStrategy; import software.amazon.awssdk.retries.LegacyRetryStrategy; import software.amazon.awssdk.retries.StandardRetryStrategy; +import software.amazon.awssdk.retries.api.BackoffStrategy; import software.amazon.awssdk.retries.api.RetryStrategy; +import software.amazon.awssdk.retries.internal.BaseRetryStrategy; /** * Retry strategies used by any SDK client. @@ -34,6 +36,8 @@ @SdkPublicApi public final class SdkDefaultRetryStrategy { + public static final String DEFAULTS_NAME = "sdk"; + private SdkDefaultRetryStrategy() { } @@ -153,7 +157,6 @@ public static AdaptiveRetryStrategy.Builder adaptiveRetryStrategyBuilder() { * @param The type of the builder extending {@link RetryStrategy.Builder} * @return The given builder */ - public static > T configure(T builder) { builder.retryOnException(SdkDefaultRetryStrategy::retryOnRetryableException) .retryOnException(SdkDefaultRetryStrategy::retryOnStatusCodes) @@ -165,6 +168,10 @@ public static AdaptiveRetryStrategy.Builder adaptiveRetryStrategyBuilder() { if (maxAttempts != null) { builder.maxAttempts(maxAttempts); } + if (builder instanceof BaseRetryStrategy.Builder) { + BaseRetryStrategy.Builder b = (BaseRetryStrategy.Builder) builder; + b.markDefaultAdded(DEFAULTS_NAME); + } return builder; } @@ -230,5 +237,17 @@ private static RetryStrategy legacyAdaptiveRetryStrategy() { .retryPolicy(RetryPolicy.forRetryMode(RetryMode.ADAPTIVE)) .build(); } + + public static void applyDefault(RetryStrategy.Builder builder) { + configureStrategy(builder); + markDefaultsAdded(builder); + } + + private static void markDefaultsAdded(RetryStrategy.Builder builder) { + if (builder instanceof BaseRetryStrategy.Builder) { + BaseRetryStrategy.Builder b = (BaseRetryStrategy.Builder) builder; + b.markDefaultAdded(DEFAULTS_NAME); + } + } } From 058d05a0931830653cae9633578701a7f59a7570 Mon Sep 17 00:00:00 2001 From: Olivier Lepage-Applin Date: Fri, 22 Nov 2024 12:51:45 -0500 Subject: [PATCH 2/7] changelog, checkstyle --- .changes/next-release/bugfix-AWSSDKforJavav2-ac30dda.json | 6 ++++++ .../awscore/client/builder/AwsDefaultClientBuilder.java | 1 - .../awssdk/core/internal/retry/SdkDefaultRetryStrategy.java | 1 - 3 files changed, 6 insertions(+), 2 deletions(-) create mode 100644 .changes/next-release/bugfix-AWSSDKforJavav2-ac30dda.json diff --git a/.changes/next-release/bugfix-AWSSDKforJavav2-ac30dda.json b/.changes/next-release/bugfix-AWSSDKforJavav2-ac30dda.json new file mode 100644 index 000000000000..68b8ee75804c --- /dev/null +++ b/.changes/next-release/bugfix-AWSSDKforJavav2-ac30dda.json @@ -0,0 +1,6 @@ +{ + "type": "bugfix", + "category": "AWS SDK for Java v2", + "contributor": "", + "description": "Add default retry predicates on top of user-provided ones" +} diff --git a/core/aws-core/src/main/java/software/amazon/awssdk/awscore/client/builder/AwsDefaultClientBuilder.java b/core/aws-core/src/main/java/software/amazon/awssdk/awscore/client/builder/AwsDefaultClientBuilder.java index e4d8b31ce614..8d16bfcbc018 100644 --- a/core/aws-core/src/main/java/software/amazon/awssdk/awscore/client/builder/AwsDefaultClientBuilder.java +++ b/core/aws-core/src/main/java/software/amazon/awssdk/awscore/client/builder/AwsDefaultClientBuilder.java @@ -24,7 +24,6 @@ import java.util.Arrays; import java.util.List; import java.util.Optional; -import java.util.function.Consumer; import java.util.function.Supplier; import software.amazon.awssdk.annotations.SdkProtectedApi; import software.amazon.awssdk.annotations.SdkTestInternalApi; diff --git a/core/sdk-core/src/main/java/software/amazon/awssdk/core/internal/retry/SdkDefaultRetryStrategy.java b/core/sdk-core/src/main/java/software/amazon/awssdk/core/internal/retry/SdkDefaultRetryStrategy.java index 74d17e005d7c..5f2fc858882f 100644 --- a/core/sdk-core/src/main/java/software/amazon/awssdk/core/internal/retry/SdkDefaultRetryStrategy.java +++ b/core/sdk-core/src/main/java/software/amazon/awssdk/core/internal/retry/SdkDefaultRetryStrategy.java @@ -26,7 +26,6 @@ import software.amazon.awssdk.retries.DefaultRetryStrategy; import software.amazon.awssdk.retries.LegacyRetryStrategy; import software.amazon.awssdk.retries.StandardRetryStrategy; -import software.amazon.awssdk.retries.api.BackoffStrategy; import software.amazon.awssdk.retries.api.RetryStrategy; import software.amazon.awssdk.retries.internal.BaseRetryStrategy; From 7195bdf011158c737188daca6a26aadac178ad71 Mon Sep 17 00:00:00 2001 From: Olivier Lepage-Applin Date: Fri, 22 Nov 2024 13:06:47 -0500 Subject: [PATCH 3/7] checkstyle, to string --- .../builder/DefaultAwsClientBuilderTest.java | 3 ++ .../retries/internal/BaseRetryStrategy.java | 33 +++++++++---------- .../DefaultAdaptiveRetryStrategy.java | 1 - 3 files changed, 18 insertions(+), 19 deletions(-) diff --git a/core/aws-core/src/test/java/software/amazon/awssdk/awscore/client/builder/DefaultAwsClientBuilderTest.java b/core/aws-core/src/test/java/software/amazon/awssdk/awscore/client/builder/DefaultAwsClientBuilderTest.java index 2b29e017ebd2..c2d5c7a0942e 100644 --- a/core/aws-core/src/test/java/software/amazon/awssdk/awscore/client/builder/DefaultAwsClientBuilderTest.java +++ b/core/aws-core/src/test/java/software/amazon/awssdk/awscore/client/builder/DefaultAwsClientBuilderTest.java @@ -59,6 +59,7 @@ import software.amazon.awssdk.http.async.SdkAsyncHttpClient; import software.amazon.awssdk.regions.Region; import software.amazon.awssdk.retries.AdaptiveRetryStrategy; +import software.amazon.awssdk.retries.DefaultRetryStrategy; import software.amazon.awssdk.retries.LegacyRetryStrategy; import software.amazon.awssdk.retries.StandardRetryStrategy; import software.amazon.awssdk.retries.api.BackoffStrategy; @@ -287,6 +288,8 @@ private static Stream retryArguments() { return Stream.of( Arguments.of("Standard - static method creation", SdkDefaultRetryStrategy.standardRetryStrategy(), 9), + Arguments.of("Standard - static builder method", + DefaultRetryStrategy.standardStrategyBuilder().build(), 9), Arguments.of("Standard - builder with retryOnException", StandardRetryStrategy.builder() .retryOnException(TestException.class) diff --git a/core/retries/src/main/java/software/amazon/awssdk/retries/internal/BaseRetryStrategy.java b/core/retries/src/main/java/software/amazon/awssdk/retries/internal/BaseRetryStrategy.java index 3a25e4315b1f..7c012a2ae119 100644 --- a/core/retries/src/main/java/software/amazon/awssdk/retries/internal/BaseRetryStrategy.java +++ b/core/retries/src/main/java/software/amazon/awssdk/retries/internal/BaseRetryStrategy.java @@ -17,7 +17,6 @@ import java.time.Duration; import java.util.ArrayList; -import java.util.Arrays; import java.util.Collections; import java.util.HashSet; import java.util.List; @@ -40,10 +39,9 @@ import software.amazon.awssdk.retries.internal.circuitbreaker.ReleaseResponse; import software.amazon.awssdk.retries.internal.circuitbreaker.TokenBucket; import software.amazon.awssdk.retries.internal.circuitbreaker.TokenBucketStore; -import software.amazon.awssdk.utils.CollectionUtils; import software.amazon.awssdk.utils.Logger; +import software.amazon.awssdk.utils.ToString; import software.amazon.awssdk.utils.Validate; -import software.amazon.awssdk.utils.builder.SdkBuilder; /** * Generic class that implements that common logic for all the retries strategies with extension points for specific strategies to @@ -372,19 +370,18 @@ static DefaultRetryToken asDefaultRetryToken(RetryToken token) { @Override public String toString() { - final StringBuilder sb = new StringBuilder("BaseRetryStrategy{"); - sb.append("retryPredicates=").append(retryPredicates); - sb.append(", maxAttempts=").append(maxAttempts); - sb.append(", circuitBreakerEnabled=").append(circuitBreakerEnabled); - sb.append(", backoffStrategy=").append(backoffStrategy); - sb.append(", throttlingBackoffStrategy=").append(throttlingBackoffStrategy); - sb.append(", treatAsThrottling=").append(treatAsThrottling); - sb.append(", exceptionCost=").append(exceptionCost); - sb.append(", tokenBucketStore=").append(tokenBucketStore); - sb.append(", defaultsAdded=").append(defaultsAdded); - sb.append(", useClientDefaults=").append(useClientDefaults); - sb.append('}'); - return sb.toString(); + return ToString.builder("BaseRetryStrategy") + .add("retryPredicates", retryPredicates) + .add("maxAttempts", maxAttempts) + .add("circuitBreakerEnabled", circuitBreakerEnabled) + .add("backoffStrategy", backoffStrategy) + .add("throttlingBackoffStrategy", throttlingBackoffStrategy) + .add("treatAsThrottling", treatAsThrottling) + .add("exceptionCost", exceptionCost) + .add("tokenBucketStore", tokenBucketStore) + .add("defaultsAdded", defaultsAdded) + .add("useClientDefaults", useClientDefaults) + .build(); } public boolean shouldAddDefaults(String defaultPredicateName) { @@ -394,15 +391,15 @@ public boolean shouldAddDefaults(String defaultPredicateName) { @SdkProtectedApi public abstract static class Builder { private List> retryPredicates; + protected Set defaultsAdded; private int maxAttempts; private Boolean circuitBreakerEnabled; + private Boolean useClientDefaults; private Integer exceptionCost; private BackoffStrategy backoffStrategy; private BackoffStrategy throttlingBackoffStrategy; private Predicate treatAsThrottling = throwable -> false; private TokenBucketStore tokenBucketStore; - protected Set defaultsAdded; - private Boolean useClientDefaults; Builder() { retryPredicates = new ArrayList<>(); diff --git a/core/retries/src/main/java/software/amazon/awssdk/retries/internal/DefaultAdaptiveRetryStrategy.java b/core/retries/src/main/java/software/amazon/awssdk/retries/internal/DefaultAdaptiveRetryStrategy.java index 19cb807341f0..e5e56b602b39 100644 --- a/core/retries/src/main/java/software/amazon/awssdk/retries/internal/DefaultAdaptiveRetryStrategy.java +++ b/core/retries/src/main/java/software/amazon/awssdk/retries/internal/DefaultAdaptiveRetryStrategy.java @@ -22,7 +22,6 @@ import software.amazon.awssdk.retries.api.AcquireInitialTokenRequest; import software.amazon.awssdk.retries.api.BackoffStrategy; import software.amazon.awssdk.retries.api.RefreshRetryTokenRequest; -import software.amazon.awssdk.retries.api.RetryStrategy; import software.amazon.awssdk.retries.internal.circuitbreaker.TokenBucketStore; import software.amazon.awssdk.retries.internal.ratelimiter.RateLimiterTokenBucket; import software.amazon.awssdk.retries.internal.ratelimiter.RateLimiterTokenBucketStore; From 64ce6b6d37119aa3d6f0c0c34939d5aa89ec6825 Mon Sep 17 00:00:00 2001 From: Olivier Lepage-Applin Date: Fri, 22 Nov 2024 13:15:09 -0500 Subject: [PATCH 4/7] checkstyle, cleanup --- .../amazon/awssdk/retries/internal/BaseRetryStrategy.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/retries/src/main/java/software/amazon/awssdk/retries/internal/BaseRetryStrategy.java b/core/retries/src/main/java/software/amazon/awssdk/retries/internal/BaseRetryStrategy.java index 7c012a2ae119..e45042594196 100644 --- a/core/retries/src/main/java/software/amazon/awssdk/retries/internal/BaseRetryStrategy.java +++ b/core/retries/src/main/java/software/amazon/awssdk/retries/internal/BaseRetryStrategy.java @@ -391,7 +391,7 @@ public boolean shouldAddDefaults(String defaultPredicateName) { @SdkProtectedApi public abstract static class Builder { private List> retryPredicates; - protected Set defaultsAdded; + private Set defaultsAdded; private int maxAttempts; private Boolean circuitBreakerEnabled; private Boolean useClientDefaults; From 7f847760494f81cd2e87fc568d8e1394ca619cfe Mon Sep 17 00:00:00 2001 From: Olivier Lepage-Applin Date: Thu, 28 Nov 2024 11:30:25 -0500 Subject: [PATCH 5/7] use a new protected api, DefaultAwareRetryStrategy, for the methods related to default retry predicates in AwsDefaultClientBuilder --- .../builder/AwsDefaultClientBuilder.java | 18 ++++---- .../awscore/retry/AwsRetryStrategy.java | 8 ++-- .../retries/internal/BaseRetryStrategy.java | 16 +++---- .../internal/DefaultAwareRetryStrategy.java | 46 +++++++++++++++++++ .../retry/SdkDefaultRetryStrategy.java | 12 ++--- 5 files changed, 73 insertions(+), 27 deletions(-) create mode 100644 core/retries/src/main/java/software/amazon/awssdk/retries/internal/DefaultAwareRetryStrategy.java diff --git a/core/aws-core/src/main/java/software/amazon/awssdk/awscore/client/builder/AwsDefaultClientBuilder.java b/core/aws-core/src/main/java/software/amazon/awssdk/awscore/client/builder/AwsDefaultClientBuilder.java index 8d16bfcbc018..5d2035cc2db8 100644 --- a/core/aws-core/src/main/java/software/amazon/awssdk/awscore/client/builder/AwsDefaultClientBuilder.java +++ b/core/aws-core/src/main/java/software/amazon/awssdk/awscore/client/builder/AwsDefaultClientBuilder.java @@ -65,7 +65,7 @@ import software.amazon.awssdk.regions.ServiceMetadataAdvancedOption; import software.amazon.awssdk.regions.providers.DefaultAwsRegionProviderChain; import software.amazon.awssdk.retries.api.RetryStrategy; -import software.amazon.awssdk.retries.internal.BaseRetryStrategy; +import software.amazon.awssdk.retries.internal.DefaultAwareRetryStrategy; import software.amazon.awssdk.utils.AttributeMap; import software.amazon.awssdk.utils.AttributeMap.LazyValueSource; import software.amazon.awssdk.utils.CollectionUtils; @@ -430,22 +430,22 @@ private void configureRetryStrategy(SdkClientConfiguration.Builder config) { return; } - if (!(strategy instanceof BaseRetryStrategy)) { + if (!(strategy instanceof DefaultAwareRetryStrategy)) { return; } - BaseRetryStrategy baseRetryStrategy = (BaseRetryStrategy) strategy; - RetryStrategy.Builder baseRetryStrategyBuilder = baseRetryStrategy.toBuilder(); + DefaultAwareRetryStrategy defaultAwareRetryStrategy = (DefaultAwareRetryStrategy) strategy; + RetryStrategy.Builder strategyBuilder = strategy.toBuilder(); - if (baseRetryStrategy.shouldAddDefaults(AwsRetryStrategy.DEFAULTS_NAME)) { - baseRetryStrategyBuilder.applyMutation(AwsRetryStrategy::applyDefault); + if (defaultAwareRetryStrategy.shouldAddDefaults(AwsRetryStrategy.DEFAULTS_NAME)) { + strategyBuilder.applyMutation(AwsRetryStrategy::applyDefaults); } - if (baseRetryStrategy.shouldAddDefaults(SdkDefaultRetryStrategy.DEFAULTS_NAME)) { - baseRetryStrategyBuilder.applyMutation(SdkDefaultRetryStrategy::applyDefault); + if (defaultAwareRetryStrategy.shouldAddDefaults(SdkDefaultRetryStrategy.DEFAULTS_NAME)) { + strategyBuilder.applyMutation(SdkDefaultRetryStrategy::applyDefaults); } - config.option(SdkClientOption.RETRY_STRATEGY, baseRetryStrategyBuilder.build()); + config.option(SdkClientOption.RETRY_STRATEGY, strategyBuilder.build()); } diff --git a/core/aws-core/src/main/java/software/amazon/awssdk/awscore/retry/AwsRetryStrategy.java b/core/aws-core/src/main/java/software/amazon/awssdk/awscore/retry/AwsRetryStrategy.java index 3bf54b6bfc5b..e238370d8b07 100644 --- a/core/aws-core/src/main/java/software/amazon/awssdk/awscore/retry/AwsRetryStrategy.java +++ b/core/aws-core/src/main/java/software/amazon/awssdk/awscore/retry/AwsRetryStrategy.java @@ -26,7 +26,7 @@ import software.amazon.awssdk.retries.LegacyRetryStrategy; import software.amazon.awssdk.retries.StandardRetryStrategy; import software.amazon.awssdk.retries.api.RetryStrategy; -import software.amazon.awssdk.retries.internal.BaseRetryStrategy; +import software.amazon.awssdk.retries.internal.DefaultAwareRetryStrategy; /** * Retry strategies used by clients when communicating with AWS services. @@ -167,14 +167,14 @@ private static RetryStrategy legacyAdaptiveRetryStrategy() { .build(); } - public static void applyDefault(RetryStrategy.Builder builder) { + public static void applyDefaults(RetryStrategy.Builder builder) { configureStrategy(builder); markDefaultsAdded(builder); } private static void markDefaultsAdded(RetryStrategy.Builder builder) { - if (builder instanceof BaseRetryStrategy.Builder) { - BaseRetryStrategy.Builder b = (BaseRetryStrategy.Builder) builder; + if (builder instanceof DefaultAwareRetryStrategy.Builder) { + DefaultAwareRetryStrategy.Builder b = (DefaultAwareRetryStrategy.Builder) builder; b.markDefaultAdded(DEFAULTS_NAME); } } diff --git a/core/retries/src/main/java/software/amazon/awssdk/retries/internal/BaseRetryStrategy.java b/core/retries/src/main/java/software/amazon/awssdk/retries/internal/BaseRetryStrategy.java index e45042594196..bea91340c20f 100644 --- a/core/retries/src/main/java/software/amazon/awssdk/retries/internal/BaseRetryStrategy.java +++ b/core/retries/src/main/java/software/amazon/awssdk/retries/internal/BaseRetryStrategy.java @@ -23,7 +23,6 @@ import java.util.Set; import java.util.function.Predicate; import software.amazon.awssdk.annotations.SdkInternalApi; -import software.amazon.awssdk.annotations.SdkProtectedApi; import software.amazon.awssdk.retries.api.AcquireInitialTokenRequest; import software.amazon.awssdk.retries.api.AcquireInitialTokenResponse; import software.amazon.awssdk.retries.api.BackoffStrategy; @@ -48,7 +47,7 @@ * tailor the behavior to its needs. */ @SdkInternalApi -public abstract class BaseRetryStrategy implements RetryStrategy { +public abstract class BaseRetryStrategy implements RetryStrategy, DefaultAwareRetryStrategy { protected final Logger log; protected final List> retryPredicates; @@ -368,6 +367,11 @@ static DefaultRetryToken asDefaultRetryToken(RetryToken token) { token.getClass().getName()); } + @Override + public boolean shouldAddDefaults(String defaultPredicateName) { + return useClientDefaults && !defaultsAdded.contains(defaultPredicateName); + } + @Override public String toString() { return ToString.builder("BaseRetryStrategy") @@ -384,12 +388,8 @@ public String toString() { .build(); } - public boolean shouldAddDefaults(String defaultPredicateName) { - return useClientDefaults && !defaultsAdded.contains(defaultPredicateName); - } - @SdkProtectedApi - public abstract static class Builder { + public abstract static class Builder implements DefaultAwareRetryStrategy.Builder { private List> retryPredicates; private Set defaultsAdded; private int maxAttempts; @@ -454,9 +454,9 @@ void setUseClientDefaults(Boolean useClientDefaults) { this.useClientDefaults = useClientDefaults; } + @Override public void markDefaultAdded(String d) { defaultsAdded.add(d); } - } } diff --git a/core/retries/src/main/java/software/amazon/awssdk/retries/internal/DefaultAwareRetryStrategy.java b/core/retries/src/main/java/software/amazon/awssdk/retries/internal/DefaultAwareRetryStrategy.java new file mode 100644 index 000000000000..32d6f16bf173 --- /dev/null +++ b/core/retries/src/main/java/software/amazon/awssdk/retries/internal/DefaultAwareRetryStrategy.java @@ -0,0 +1,46 @@ +/* + * Copyright 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 software.amazon.awssdk.retries.internal; + +import software.amazon.awssdk.annotations.SdkProtectedApi; +import software.amazon.awssdk.retries.api.RetryStrategy; + +/** + * Identify a {@link RetryStrategy} that has the capacity to work with sets of default retry predicates. + */ +@SdkProtectedApi +public interface DefaultAwareRetryStrategy { + + /** + * Check if the specified set of predicates, identified by their name, has been added to this retry strategy + * @param defaultPredicatesName the name of the set of predicates to check + * @return true if the named set of predicate + */ + default boolean shouldAddDefaults(String defaultPredicatesName) { + return false; + } + + interface Builder { + + /** + * Identify the Builder has having the specified set of predicate added to it. + * @param defaultPredicatesName the name of the set of predicate + */ + default void markDefaultAdded(String defaultPredicatesName) { + + } + } +} diff --git a/core/sdk-core/src/main/java/software/amazon/awssdk/core/internal/retry/SdkDefaultRetryStrategy.java b/core/sdk-core/src/main/java/software/amazon/awssdk/core/internal/retry/SdkDefaultRetryStrategy.java index 5f2fc858882f..0d16646646b1 100644 --- a/core/sdk-core/src/main/java/software/amazon/awssdk/core/internal/retry/SdkDefaultRetryStrategy.java +++ b/core/sdk-core/src/main/java/software/amazon/awssdk/core/internal/retry/SdkDefaultRetryStrategy.java @@ -27,7 +27,7 @@ import software.amazon.awssdk.retries.LegacyRetryStrategy; import software.amazon.awssdk.retries.StandardRetryStrategy; import software.amazon.awssdk.retries.api.RetryStrategy; -import software.amazon.awssdk.retries.internal.BaseRetryStrategy; +import software.amazon.awssdk.retries.internal.DefaultAwareRetryStrategy; /** * Retry strategies used by any SDK client. @@ -167,8 +167,8 @@ public static AdaptiveRetryStrategy.Builder adaptiveRetryStrategyBuilder() { if (maxAttempts != null) { builder.maxAttempts(maxAttempts); } - if (builder instanceof BaseRetryStrategy.Builder) { - BaseRetryStrategy.Builder b = (BaseRetryStrategy.Builder) builder; + if (builder instanceof DefaultAwareRetryStrategy.Builder) { + DefaultAwareRetryStrategy.Builder b = (DefaultAwareRetryStrategy.Builder) builder; b.markDefaultAdded(DEFAULTS_NAME); } return builder; @@ -237,14 +237,14 @@ private static RetryStrategy legacyAdaptiveRetryStrategy() { .build(); } - public static void applyDefault(RetryStrategy.Builder builder) { + public static void applyDefaults(RetryStrategy.Builder builder) { configureStrategy(builder); markDefaultsAdded(builder); } private static void markDefaultsAdded(RetryStrategy.Builder builder) { - if (builder instanceof BaseRetryStrategy.Builder) { - BaseRetryStrategy.Builder b = (BaseRetryStrategy.Builder) builder; + if (builder instanceof DefaultAwareRetryStrategy.Builder) { + DefaultAwareRetryStrategy.Builder b = (DefaultAwareRetryStrategy.Builder) builder; b.markDefaultAdded(DEFAULTS_NAME); } } From 62336f3927d16fd620a8facc601bed4e0f8196e4 Mon Sep 17 00:00:00 2001 From: Olivier Lepage-Applin Date: Tue, 3 Dec 2024 11:13:19 -0500 Subject: [PATCH 6/7] add defaults explicitly to the retry strategy builder using RetryStrategyDefaults interface --- .../builder/AwsDefaultClientBuilder.java | 13 ++----- .../awscore/retry/AwsRetryStrategy.java | 21 ++++++++-- .../builder/DefaultAwsClientBuilderTest.java | 33 ++++++++++++++-- .../retries/internal/BaseRetryStrategy.java | 15 +++++++- .../internal/DefaultAwareRetryStrategy.java | 20 ++++------ .../internal/RetryStrategyDefaults.java | 38 +++++++++++++++++++ .../retry/SdkDefaultRetryStrategy.java | 22 +++++++++-- 7 files changed, 126 insertions(+), 36 deletions(-) create mode 100644 core/retries/src/main/java/software/amazon/awssdk/retries/internal/RetryStrategyDefaults.java diff --git a/core/aws-core/src/main/java/software/amazon/awssdk/awscore/client/builder/AwsDefaultClientBuilder.java b/core/aws-core/src/main/java/software/amazon/awssdk/awscore/client/builder/AwsDefaultClientBuilder.java index 5d2035cc2db8..0b4f28050210 100644 --- a/core/aws-core/src/main/java/software/amazon/awssdk/awscore/client/builder/AwsDefaultClientBuilder.java +++ b/core/aws-core/src/main/java/software/amazon/awssdk/awscore/client/builder/AwsDefaultClientBuilder.java @@ -433,18 +433,11 @@ private void configureRetryStrategy(SdkClientConfiguration.Builder config) { if (!(strategy instanceof DefaultAwareRetryStrategy)) { return; } - DefaultAwareRetryStrategy defaultAwareRetryStrategy = (DefaultAwareRetryStrategy) strategy; - RetryStrategy.Builder strategyBuilder = strategy.toBuilder(); - - if (defaultAwareRetryStrategy.shouldAddDefaults(AwsRetryStrategy.DEFAULTS_NAME)) { - strategyBuilder.applyMutation(AwsRetryStrategy::applyDefaults); - } - - if (defaultAwareRetryStrategy.shouldAddDefaults(SdkDefaultRetryStrategy.DEFAULTS_NAME)) { - strategyBuilder.applyMutation(SdkDefaultRetryStrategy::applyDefaults); - } + defaultAwareRetryStrategy = defaultAwareRetryStrategy.addDefaults(AwsRetryStrategy.retryStrategyDefaults()); + defaultAwareRetryStrategy = defaultAwareRetryStrategy.addDefaults(SdkDefaultRetryStrategy.retryStrategyDefaults()); + RetryStrategy.Builder strategyBuilder = defaultAwareRetryStrategy.toBuilder(); config.option(SdkClientOption.RETRY_STRATEGY, strategyBuilder.build()); } diff --git a/core/aws-core/src/main/java/software/amazon/awssdk/awscore/retry/AwsRetryStrategy.java b/core/aws-core/src/main/java/software/amazon/awssdk/awscore/retry/AwsRetryStrategy.java index e238370d8b07..829793f9e341 100644 --- a/core/aws-core/src/main/java/software/amazon/awssdk/awscore/retry/AwsRetryStrategy.java +++ b/core/aws-core/src/main/java/software/amazon/awssdk/awscore/retry/AwsRetryStrategy.java @@ -27,6 +27,7 @@ import software.amazon.awssdk.retries.StandardRetryStrategy; import software.amazon.awssdk.retries.api.RetryStrategy; import software.amazon.awssdk.retries.internal.DefaultAwareRetryStrategy; +import software.amazon.awssdk.retries.internal.RetryStrategyDefaults; /** * Retry strategies used by clients when communicating with AWS services. @@ -34,7 +35,20 @@ @SdkPublicApi public final class AwsRetryStrategy { - public static final String DEFAULTS_NAME = "aws"; + private static final String DEFAULTS_NAME = "aws"; + + private static final RetryStrategyDefaults DEFAULTS_PREDICATES = new RetryStrategyDefaults() { + @Override + public String name() { + return DEFAULTS_NAME; + } + + @Override + public void applyDefault(RetryStrategy.Builder retryStrategyBuilder) { + configureStrategy(retryStrategyBuilder); + markDefaultsAdded(retryStrategyBuilder); + } + }; private AwsRetryStrategy() { } @@ -167,9 +181,8 @@ private static RetryStrategy legacyAdaptiveRetryStrategy() { .build(); } - public static void applyDefaults(RetryStrategy.Builder builder) { - configureStrategy(builder); - markDefaultsAdded(builder); + public static RetryStrategyDefaults retryStrategyDefaults() { + return DEFAULTS_PREDICATES; } private static void markDefaultsAdded(RetryStrategy.Builder builder) { diff --git a/core/aws-core/src/test/java/software/amazon/awssdk/awscore/client/builder/DefaultAwsClientBuilderTest.java b/core/aws-core/src/test/java/software/amazon/awssdk/awscore/client/builder/DefaultAwsClientBuilderTest.java index c2d5c7a0942e..74d263c68f43 100644 --- a/core/aws-core/src/test/java/software/amazon/awssdk/awscore/client/builder/DefaultAwsClientBuilderTest.java +++ b/core/aws-core/src/test/java/software/amazon/awssdk/awscore/client/builder/DefaultAwsClientBuilderTest.java @@ -35,6 +35,7 @@ import java.time.Duration; import java.util.Arrays; import java.util.Optional; +import java.util.function.Predicate; import java.util.stream.Stream; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -43,7 +44,6 @@ import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; import org.mockito.Mock; -import org.mockito.junit.MockitoJUnit; import software.amazon.awssdk.auth.credentials.AnonymousCredentialsProvider; import software.amazon.awssdk.auth.signer.Aws4Signer; import software.amazon.awssdk.awscore.client.config.AwsClientOption; @@ -267,7 +267,7 @@ public void clientBuilderFieldsHaveBeanEquivalents() throws Exception { @ParameterizedTest(name = "{0} - expectedPredicateAmount: {2}") @MethodSource("retryArguments") - public void retryStrategyConfiguration_shouldAddDefaultPredicatesWhenRequired( + void retryStrategyConfiguration_shouldAddDefaultPredicatesWhenRequired( String testDescription, RetryStrategy retryStrategy, int expectedPredicateAmount) { TestClientBuilder builder = testClientBuilder() .region(Region.US_EAST_1) @@ -279,8 +279,8 @@ public void retryStrategyConfiguration_shouldAddDefaultPredicatesWhenRequired( RetryStrategy configuredRetryStrategy = conf.retryStrategy().get(); BaseRetryStrategy baseRetryStrategy = (BaseRetryStrategy) configuredRetryStrategy; - assertThat(baseRetryStrategy.shouldAddDefaults(AwsRetryStrategy.DEFAULTS_NAME)).isFalse(); - assertThat(baseRetryStrategy.shouldAddDefaults(SdkDefaultRetryStrategy.DEFAULTS_NAME)).isFalse(); + assertThat(baseRetryStrategy.shouldAddDefaults(AwsRetryStrategy.retryStrategyDefaults().name())).isFalse(); + assertThat(baseRetryStrategy.shouldAddDefaults(SdkDefaultRetryStrategy.retryStrategyDefaults().name())).isFalse(); assertThat(baseRetryStrategy.retryPredicates()).hasSize(expectedPredicateAmount); } @@ -336,6 +336,31 @@ private static Stream retryArguments() { ); } + @ParameterizedTest(name = "{0} - expectedPredicateAmount: ({2}+2)") + @MethodSource("retryArguments") + void retryBuilderRoundTrip_ShouldKeepDefaults_ShouldAddNewPredicates( + String testDescription, RetryStrategy retryStrategy, int expectedPredicateAmount) { + RetryStrategy.Builder retryBuilder = retryStrategy.toBuilder(); + Predicate newDummyPredicate1 = t -> t instanceof RuntimeException; + Predicate newDummyPredicate2 = t -> t instanceof IllegalArgumentException; + retryBuilder.retryOnException(newDummyPredicate1); + retryBuilder.retryOnException(newDummyPredicate2); + + TestClientBuilder clientBuilder = testClientBuilder() + .region(Region.US_EAST_1) + .overrideConfiguration(c -> c.retryStrategy(retryBuilder.build())); + TestClient client = clientBuilder.build(); + + ClientOverrideConfiguration conf = client.clientConfiguration.asOverrideConfiguration(); + assertThat(conf.retryStrategy()).isPresent(); + + RetryStrategy configuredRetryStrategy = conf.retryStrategy().get(); + BaseRetryStrategy baseRetryStrategy = (BaseRetryStrategy) configuredRetryStrategy; + assertThat(baseRetryStrategy.shouldAddDefaults(AwsRetryStrategy.retryStrategyDefaults().name())).isFalse(); + assertThat(baseRetryStrategy.shouldAddDefaults(SdkDefaultRetryStrategy.retryStrategyDefaults().name())).isFalse(); + assertThat(baseRetryStrategy.retryPredicates()).hasSize(expectedPredicateAmount + 2); + } + private AwsClientBuilder testClientBuilder() { ClientOverrideConfiguration overrideConfig = ClientOverrideConfiguration.builder() diff --git a/core/retries/src/main/java/software/amazon/awssdk/retries/internal/BaseRetryStrategy.java b/core/retries/src/main/java/software/amazon/awssdk/retries/internal/BaseRetryStrategy.java index bea91340c20f..c5c439da5d66 100644 --- a/core/retries/src/main/java/software/amazon/awssdk/retries/internal/BaseRetryStrategy.java +++ b/core/retries/src/main/java/software/amazon/awssdk/retries/internal/BaseRetryStrategy.java @@ -47,7 +47,7 @@ * tailor the behavior to its needs. */ @SdkInternalApi -public abstract class BaseRetryStrategy implements RetryStrategy, DefaultAwareRetryStrategy { +public abstract class BaseRetryStrategy implements DefaultAwareRetryStrategy { protected final Logger log; protected final List> retryPredicates; @@ -367,11 +367,21 @@ static DefaultRetryToken asDefaultRetryToken(RetryToken token) { token.getClass().getName()); } - @Override + public boolean shouldAddDefaults(String defaultPredicateName) { return useClientDefaults && !defaultsAdded.contains(defaultPredicateName); } + @Override + public DefaultAwareRetryStrategy addDefaults(RetryStrategyDefaults retryStrategyDefaults) { + if (!shouldAddDefaults(retryStrategyDefaults.name())) { + return this; + } + RetryStrategy.Builder builder = this.toBuilder(); + retryStrategyDefaults.applyDefault(builder); + return (DefaultAwareRetryStrategy) builder.build(); + } + @Override public String toString() { return ToString.builder("BaseRetryStrategy") @@ -416,6 +426,7 @@ public abstract static class Builder implements DefaultAwareRetryStrategy.Builde this.treatAsThrottling = strategy.treatAsThrottling; this.tokenBucketStore = strategy.tokenBucketStore; this.defaultsAdded = strategy.defaultsAdded; + this.useClientDefaults = strategy.useClientDefaults; } void setRetryOnException(Predicate shouldRetry) { diff --git a/core/retries/src/main/java/software/amazon/awssdk/retries/internal/DefaultAwareRetryStrategy.java b/core/retries/src/main/java/software/amazon/awssdk/retries/internal/DefaultAwareRetryStrategy.java index 32d6f16bf173..a36bf9b7ad03 100644 --- a/core/retries/src/main/java/software/amazon/awssdk/retries/internal/DefaultAwareRetryStrategy.java +++ b/core/retries/src/main/java/software/amazon/awssdk/retries/internal/DefaultAwareRetryStrategy.java @@ -22,25 +22,21 @@ * Identify a {@link RetryStrategy} that has the capacity to work with sets of default retry predicates. */ @SdkProtectedApi -public interface DefaultAwareRetryStrategy { +public interface DefaultAwareRetryStrategy extends RetryStrategy { /** - * Check if the specified set of predicates, identified by their name, has been added to this retry strategy - * @param defaultPredicatesName the name of the set of predicates to check - * @return true if the named set of predicate + * Add the specified defaults to this retry strategy + * @param retryStrategyDefaults the defaults to add to this strategy + * @return a new retry strategy containing the specified defaults. */ - default boolean shouldAddDefaults(String defaultPredicatesName) { - return false; - } + DefaultAwareRetryStrategy addDefaults(RetryStrategyDefaults retryStrategyDefaults); interface Builder { /** - * Identify the Builder has having the specified set of predicate added to it. - * @param defaultPredicatesName the name of the set of predicate + * Identify the Builder as having the specified defaults to it. + * @param defaultPredicatesName the name the defaults to mark as added */ - default void markDefaultAdded(String defaultPredicatesName) { - - } + void markDefaultAdded(String defaultPredicatesName); } } diff --git a/core/retries/src/main/java/software/amazon/awssdk/retries/internal/RetryStrategyDefaults.java b/core/retries/src/main/java/software/amazon/awssdk/retries/internal/RetryStrategyDefaults.java new file mode 100644 index 000000000000..a36f69610353 --- /dev/null +++ b/core/retries/src/main/java/software/amazon/awssdk/retries/internal/RetryStrategyDefaults.java @@ -0,0 +1,38 @@ +/* + * Copyright 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 software.amazon.awssdk.retries.internal; + +import software.amazon.awssdk.annotations.SdkProtectedApi; +import software.amazon.awssdk.retries.api.RetryStrategy; + +/** + * The set of retry predicates that are by default added to a retry strategy. + */ +@SdkProtectedApi +public interface RetryStrategyDefaults { + + /** + * The unique name that identifies this set of predicates + * @return + */ + String name(); + + /** + * Apply this set of defaults to the provided retry strategy builder. + * @param retryStrategyBuilder the retry strategy to apply the defaults to + */ + void applyDefault(RetryStrategy.Builder retryStrategyBuilder); +} diff --git a/core/sdk-core/src/main/java/software/amazon/awssdk/core/internal/retry/SdkDefaultRetryStrategy.java b/core/sdk-core/src/main/java/software/amazon/awssdk/core/internal/retry/SdkDefaultRetryStrategy.java index 0d16646646b1..8d1de74f1cf9 100644 --- a/core/sdk-core/src/main/java/software/amazon/awssdk/core/internal/retry/SdkDefaultRetryStrategy.java +++ b/core/sdk-core/src/main/java/software/amazon/awssdk/core/internal/retry/SdkDefaultRetryStrategy.java @@ -28,6 +28,7 @@ import software.amazon.awssdk.retries.StandardRetryStrategy; import software.amazon.awssdk.retries.api.RetryStrategy; import software.amazon.awssdk.retries.internal.DefaultAwareRetryStrategy; +import software.amazon.awssdk.retries.internal.RetryStrategyDefaults; /** * Retry strategies used by any SDK client. @@ -35,7 +36,20 @@ @SdkPublicApi public final class SdkDefaultRetryStrategy { - public static final String DEFAULTS_NAME = "sdk"; + private static final String DEFAULTS_NAME = "sdk"; + + private static final RetryStrategyDefaults DEFAULTS_PREDICATES = new RetryStrategyDefaults() { + @Override + public String name() { + return DEFAULTS_NAME; + } + + @Override + public void applyDefault(RetryStrategy.Builder builder) { + configureStrategy(builder); + markDefaultsAdded(builder); + } + }; private SdkDefaultRetryStrategy() { } @@ -237,9 +251,8 @@ private static RetryStrategy legacyAdaptiveRetryStrategy() { .build(); } - public static void applyDefaults(RetryStrategy.Builder builder) { - configureStrategy(builder); - markDefaultsAdded(builder); + public static RetryStrategyDefaults retryStrategyDefaults() { + return DEFAULTS_PREDICATES; } private static void markDefaultsAdded(RetryStrategy.Builder builder) { @@ -248,5 +261,6 @@ private static void markDefaultsAdded(RetryStrategy.Builder builder) { b.markDefaultAdded(DEFAULTS_NAME); } } + } From d49cbfcddee91bd4d9aed50f0f116612eaa99d6c Mon Sep 17 00:00:00 2001 From: Olivier Lepage-Applin Date: Tue, 3 Dec 2024 12:12:11 -0500 Subject: [PATCH 7/7] javadoc --- .../amazon/awssdk/awscore/retry/AwsRetryStrategy.java | 2 +- .../amazon/awssdk/retries/internal/BaseRetryStrategy.java | 2 +- .../awssdk/retries/internal/RetryStrategyDefaults.java | 5 ++--- .../awssdk/core/internal/retry/SdkDefaultRetryStrategy.java | 2 +- 4 files changed, 5 insertions(+), 6 deletions(-) diff --git a/core/aws-core/src/main/java/software/amazon/awssdk/awscore/retry/AwsRetryStrategy.java b/core/aws-core/src/main/java/software/amazon/awssdk/awscore/retry/AwsRetryStrategy.java index 829793f9e341..17cd00b58e08 100644 --- a/core/aws-core/src/main/java/software/amazon/awssdk/awscore/retry/AwsRetryStrategy.java +++ b/core/aws-core/src/main/java/software/amazon/awssdk/awscore/retry/AwsRetryStrategy.java @@ -44,7 +44,7 @@ public String name() { } @Override - public void applyDefault(RetryStrategy.Builder retryStrategyBuilder) { + public void applyDefaults(RetryStrategy.Builder retryStrategyBuilder) { configureStrategy(retryStrategyBuilder); markDefaultsAdded(retryStrategyBuilder); } diff --git a/core/retries/src/main/java/software/amazon/awssdk/retries/internal/BaseRetryStrategy.java b/core/retries/src/main/java/software/amazon/awssdk/retries/internal/BaseRetryStrategy.java index c5c439da5d66..2a74eef5a3a2 100644 --- a/core/retries/src/main/java/software/amazon/awssdk/retries/internal/BaseRetryStrategy.java +++ b/core/retries/src/main/java/software/amazon/awssdk/retries/internal/BaseRetryStrategy.java @@ -378,7 +378,7 @@ public DefaultAwareRetryStrategy addDefaults(RetryStrategyDefaults retryStrategy return this; } RetryStrategy.Builder builder = this.toBuilder(); - retryStrategyDefaults.applyDefault(builder); + retryStrategyDefaults.applyDefaults(builder); return (DefaultAwareRetryStrategy) builder.build(); } diff --git a/core/retries/src/main/java/software/amazon/awssdk/retries/internal/RetryStrategyDefaults.java b/core/retries/src/main/java/software/amazon/awssdk/retries/internal/RetryStrategyDefaults.java index a36f69610353..3cf2658bedec 100644 --- a/core/retries/src/main/java/software/amazon/awssdk/retries/internal/RetryStrategyDefaults.java +++ b/core/retries/src/main/java/software/amazon/awssdk/retries/internal/RetryStrategyDefaults.java @@ -25,8 +25,7 @@ public interface RetryStrategyDefaults { /** - * The unique name that identifies this set of predicates - * @return + * @return The unique name that identifies this set of predicates */ String name(); @@ -34,5 +33,5 @@ public interface RetryStrategyDefaults { * Apply this set of defaults to the provided retry strategy builder. * @param retryStrategyBuilder the retry strategy to apply the defaults to */ - void applyDefault(RetryStrategy.Builder retryStrategyBuilder); + void applyDefaults(RetryStrategy.Builder retryStrategyBuilder); } diff --git a/core/sdk-core/src/main/java/software/amazon/awssdk/core/internal/retry/SdkDefaultRetryStrategy.java b/core/sdk-core/src/main/java/software/amazon/awssdk/core/internal/retry/SdkDefaultRetryStrategy.java index 8d1de74f1cf9..bc7685b6126c 100644 --- a/core/sdk-core/src/main/java/software/amazon/awssdk/core/internal/retry/SdkDefaultRetryStrategy.java +++ b/core/sdk-core/src/main/java/software/amazon/awssdk/core/internal/retry/SdkDefaultRetryStrategy.java @@ -45,7 +45,7 @@ public String name() { } @Override - public void applyDefault(RetryStrategy.Builder builder) { + public void applyDefaults(RetryStrategy.Builder builder) { configureStrategy(builder); markDefaultsAdded(builder); }