'Exponential apiCallAttemptTimeout in AWS SDK for Java V2

I'm currently using the AWS SDK for Java v2 (specifically v2.17.1) and the S3AsyncClient::getObject method.

final GetObjectRequest getObjectRequest = GetObjectRequest.builder()
    .bucket("my bucket")
    .key("some key")
    .overrideConfiguration(AwsRequestOverrideConfiguration.builder()
        .apiCallAttemptTimeout(Duration.ofSeconds(1))
        .build())
    .build();

return s3AsyncClient
    .getObject(getObjectRequest, AsyncResponseTransformer.toBytes())
    .thenAppply(/* snipped for brevity */);

This mostly works fine, but occasionally I get bursts of these errors:

software.amazon.awssdk.core.exception.ApiCallAttemptTimeoutException: HTTP request execution did not complete before the specified timeout configuration: 1000 millis

I currently have the following configuration on the builder that creates that s3AsyncClient above:

S3AsyncClient.builder()
    // other options snipped for brevity
    .overrideConfiguration(ClientOverrideConfiguration.builder()
        .retryPolicy(RetryPolicy.builder()
            .numRetries(2)
            .build())
        .build())
    .build()

Is there a way to make it so that different apiCallAttemptTimeout values are used depending on how many retry attempts have been made? In other words, how do I get exponential retry timeouts working?

I'm aware a newer version of the SDK includes a new ADAPTIVE RetryMode option, but my understanding is that this only applies when you're being rate limited by AWS. I've also seen parts of the S3 code that can exponentially delay the time between retries, but not the timeout for each retry.

Any help is appreciated - thank you!



Solution 1:[1]

You're nearly there.

In AWS SDK v2, the concept of RetryPolicy & BackoffStrategy has been carried over from V1 though with some minor differences in terms of how to configure it.

The builder allows for some complex and unique configurations but with some digging into the documentation, you'll find a set of PredefinedBackoffStrategies with one of them being the ExponentialBackoffStrategy.

This predefined strategy allows you to set the base (initial) delay & then the max back-off duration. You can set this when creating your client.

This should help:

final int initialDelayInMilliSeconds = 1 * 1000;
final int maxDelayInMilliSeconds = 60 * 1000;

final PredefinedBackoffStrategies.ExponentialBackoffStrategy backoffStrategy =
        new PredefinedBackoffStrategies.ExponentialBackoffStrategy(
                initialDelayInMilliSeconds,
                maxDelayInMilliSeconds
        );

final RetryPolicy retryPolicy = RetryPolicy.builder()
        .backoffStrategy((BackoffStrategy) backoffStrategy)
        .build();

return S3AsyncClient.builder()
        // other options snipped for brevity
        .overrideConfiguration(ClientOverrideConfiguration.builder()
                .retryPolicy(retryPolicy)
                .build())
        .build();

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Ermiya Eskandary