Retries - Amazon SDK for Java 2.x
Services or capabilities described in Amazon Web Services documentation might vary by Region. To see the differences applicable to the China Regions, see Getting Started with Amazon Web Services in China (PDF).

Retries

Calls to Amazon Web Services can fail occasionally for unexpected reasons. Certain errors, such as throttling (rate exceeded) or transient errors, might succeed if the call is retried. The Amazon SDK for Java 2.x has a built-in mechanism to detect such errors and automatically retry the call that is enabled by default for all clients.

This page describes how this works, how to configure the distinct modes, and tailor the retry behavior.

Retry strategies

A retry strategy is a mechanism used in the SDK to implement retries. Each SDK client has a retry strategy created at build time that cannot be modified after the client is built.

The retry strategy has the following responsibilities.

  • Classify exceptions as retryable or not.

  • Compute the suggested delay to wait before the next attempt.

  • Maintain a token bucket that provides a mechanism to stop retries when a large percentage of requests are failing and retries are unsuccessful.

Note

Before the release of retry strategies with version 2.26.0 of the SDK, retry policies provided the retry mechanism in the SDK. The retry policy API is made up of the core RetryPolicy class in the software.amazon.awssdk.core.retry package, whereas the software.amazon.awssdk.retries package contains the retry strategy API elements.

The retry strategy API was introduced as part of the Amazon-wide effort to unify the interfaces and behavior of the core components of the SDKs.

The SDK for Java 2.x has three built-in retry strategies: standard, legacy, and adaptive. All three retry strategies are preconfigured to retry on a set of retryable exceptions. Examples of retryable errors are socket timeouts, service-side throttling, concurrency or optimistic lock failures, and transient service errors.

Standard retry strategy

The standard retry strategy is the recommended RetryStrategy implementation for normal use cases. Unlike the AdaptiveRetryStrategy, the standard strategy is generally useful across all retry use cases.

By default, the standard retry strategy does the following.

  • Retries on the conditions that are configured at build time. You can adjust this with StandardRetryStrategy.Builder#retryOnException.

  • Retries 2 times for a total of 3 attempts. You can adjust this with StandardRetryStrategy.Builder#maxAttempts(int).

  • Uses the BackoffStrategy#exponentialDelay backoff strategy, with a base delay of 100 milliseconds and a max delay of 20 seconds. You can adjust with StandardRetryStrategy.Builder#backoffStrategy.

  • Performs circuit breaking (disabling retries) in the event of high downstream failures. The first attempt is always executed, only retries are disabled. Adjust with StandardRetryStrategy.Builder#circuitBreakerEnabled.

Legacy retry strategy

The legacy retry strategy is a RetryStrategy for normal use cases, however, it is deprecated in favor of the StandardRetryStrategy. This is the default retry strategy used by clients when you don't specify another strategy.

It is characterized by treating throttling and non-throttling exceptions differently, for throttling exceptions the base delay for the backoff is larger (500ms) than the base delay for non-throttling exceptions (100ms), and throttling exceptions do not affect the token bucket state.

Experience using this strategy at scale inside Amazon has shown that is not particularly better than the standard retry strategy. Moreover, it fails to protect downstream services from retry storms and can lead to resource starvation on the client side.

By default, the legacy retry strategy does the following.

  • Retries on the conditions that are configured at build time. You can adjust this with LegacyRetryStrategy.Builder#retryOnException .

  • Retries 3 times for a total of 4 attempts. You can adjust this with LegacyRetryStrategy.Builder#maxAttempts(int).

  • For non-throttling exceptions, it uses the BackoffStrategy#exponentialDelay backoff strategy, with a base delay of 100 milliseconds and a max delay of 20 seconds. You can adjust this with RetryStrategy.Builder#backoffStrategy.

  • For throttling exceptions, it uses the BackoffStrategy#exponentialDelay backoff strategy, with a base delay of 500 milliseconds and a max delay of 20 seconds. You can adjust this with LegacyRetryStrategy.Builder#throttlingBackoffStrategy.

  • Performs circuit breaking (disabling retries) in the event of high downstream failures. Circuit breaking never prevents a successful first attempt. You can adjust this behavior with LegacyRetryStrategy.Builder#circuitBreakerEnabled.

  • The state of the circuit breaker is not affected by throttling exceptions.

Adaptive retry strategy

The adaptive retry strategy is a RetryStrategy for use cases with a high level of resource constraints.

The adaptive retry strategy includes all the features of the standard strategy and adds a client-side rate limiter that measures the rate of throttled requests compared to non-throttled requests. The strategy uses this measurement to slow down the requests in an attempt to stay within a safe bandwidth, ideally causing zero throttling errors.

By default, the adaptive retry strategy does the following.

  • Retries on the conditions that are configured at build time. You can adjust this with AdaptiveRetryStrategy.Builder#retryOnException .

  • Retries 2 times for a total of 3 attempts. You can adjust this with AdaptiveRetryStrategy.Builder#maxAttempts(int).

  • Uses a dynamic backoff delay that is based on the current load against the downstream resource.

  • Performs circuit breaking (disabling retries) when there are high number of downstream failures. Circuit breaking may prevent a second attempt in outage scenarios to protect the downstream service.

Warning

The adaptive retry strategy assumes that the client works against a single resource (for example, one DynamoDB table or one Amazon S3 bucket).

If you use a single client for multiple resources, throttling or outages associated with one resource result in increased latency and failures when the client accesses all other resources. When you use the adaptive retry strategy, we recommend that you use a single client for each resource.

We also recommend that the you this strategy in situations where all clients use the adaptive retry strategy against the resource.

Important

The release of retry strategies with 2.26.0 of the Java SDK includes the new RetryMode.ADAPTIVE_V2 enumeration value. The ADAPTIVE_V2 mode corrects an error that failed to delay the first attempt when throttling errors were detected previously.

With the 2.26.0 release, users automatically get the ADAPTIVE_V2 mode behavior by setting the mode as adaptive with an environment variable, system property, or profile setting. There is no adaptive_v2 value for these settings. See the following Specify a strategy section for how to set the mode.

Users can get the previous behavior by setting the mode in code using RetryMode.ADAPTIVE.

Summary: Comparison of retry strategy default values

The following table shows the default values for the properties of each retry strategy.

Strategy Maximum attempts Base delay for non-throttling errors Base delay for throttling errors Token bucket size Token cost per non-throttling retry Token cost per throttling retry
Standard 3 100 100 500 5 5
Legacy 4 100 500 500 5 0
Adaptive 3 100 100 500 5 5

Specify a strategy

You have four ways to specify a strategy for your service client.

In code

When you build a client, you can configure a lambda expression with a retry strategy. The following snippet configures a standard retry strategy that uses default values on a DynamoDB service client.

DynamoDbClient client = DynamoDbClient.builder() .overrideConfiguration(o -> o.retryStrategy(RetryMode.STANDARD)) .build();

You can specify RetryMode.LEGACY or RetryMode.ADAPTIVE in place of RetryMode.STANDARD.

As a profile setting

Include retry_mode as profile setting in the shared Amazon config file. Specify standard, legacy, or adaptive as a value. When set as a profile setting, all service clients that are created while the profile is active use the specified retry strategy with default values. You can override this setting by configuring a retry strategy in code as shown previously.

With the following profile, all service clients use the standard retry strategy.

[profile dev] region = us-east-2 retry_mode = standard

As a JVM system property

You can configure a retry stategy for all service clients, unless overridden in code, by using the system property aws.retryMode. Specify standard, legacy, or adaptive as a value.

Use the -D switch when you invoke Java as shown in the following command.

java -Daws.retryMode=standard ...

Alternatively, set the system property in the code before creating any client as shown in the following snippet.

public void main(String[] args) { // Set the property BEFORE any Amazon service clients are created. System.setProperty("aws.retryMode", "standard"); ... }

With an environment variable

You can also use the AWS_RETRY_MODE environment variable with a value of standard, legacy, or adaptive. As with a profile setting or JVM system property, the environment variable configures all service clients with the specified retry mode unless you configure a client in code.

The following command sets the retry mode to standard for the current shell session.

export AWS_RETRY_MODE=standard

Customize a strategy

You can customize any retry strategy by setting the maximum attempts, backoff strategy, and exceptions that are retryable. You can customize when you build a retry strategy or when you build a client by using a override builder that allows further refinements of the configured strategy.

Customize maximum attempts

You can configure the maximum number of attempts during client construction as shown in the following statement. The following statement customizes the default retry strategy for the client to a maximum of 5 attempt--a first attempt plus 4 retries.

DynamoDbClient client = DynamoDbClient.builder() .overrideConfiguration(o -> o.retryStrategy(b -> b.maxAttempts(5))) .build();

Alternatively, you can build the strategy and provide it to the client as in the following code example. The following code replaces the standard 3 maximum attempts with 10 and configures a DynamoDB client with the customized strategy.

StandardRetryStrategy strategy = AwsRetryStrategy.standardRetryStrategy() .toBuilder() .maxAttempts(10) .build(); DynamoDbClient client = DynamoDbClient.builder() .overrideConfiguration(o -> o.retryStrategy(strategy)) .build();
Warning

We recommended that you configure each client with a unique RetryStrategy instance. If a RetryStrategy instance is shared, failures in one client might affect the retry behavior in the other.

You can also set the maximum number of attempts for all clients by using external settings instead of code. You configure this setting as describe in the Specify a strategy section.

Customize retryable exceptions

You can configure additional exceptions that trigger retires during client construction. This customization is provided for edge cases where exceptions are thrown that are not included in the default set of retryable exceptions.

The following code snippet shows the methods you use to customize the retry exceptions--retryOnException and retryOnExceptionOrCause. The retryOnExceptionOrCause methods adds a retryable exception if the SDK throws the direct exception or if the exception is wrapped.

DynamoDbClient client = DynamoDbClient.builder() .overrideConfiguration(o -> o.retryStrategy( b -> b.retryOnException(EdgeCaseException.class) .retryOnExceptionOrCause(WrappedEdgeCaseException.class))) .build();

Customize the backoff strategy

You can build the backoff strategy and supply it to the client.

The following code builds a BackoffStrategy that replaces the default, standard strategy's exponential delay backoff strategy.

BackoffStrategy backoffStrategy = BackoffStrategy.exponentialDelay(Duration.ofMillis(150), // The base delay. Duration.ofSeconds(15)); // The maximum delay. DynamoDbClient client = DynamoDbClient.builder() .overrideConfiguration(o -> o.retryStrategy( b -> b.backoffStrategy(backoffStrategy))) .build();

Migrating from RetryPolicy to RetryStrategy

RetryPolicy (the retry policy API) will be supported for the foreseeable future. If you currently use an instance of RetryPolicy to configure your client, everything is going to work as before. Behind the scenes the Java SDK adapts it to a RetryStrategy. The new retry strategy interfaces provide the same functionality as a RetryPolicy but are created and configured differently.