Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .changes/next-release/feature-AWSSDKforJavav2-ddc21df.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"type": "feature",
"category": "AWS SDK for Java v2",
"contributor": "",
"description": "Expose StandardRetryOptions of S3ClientOptions in the S3CrtClient Interface"
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import software.amazon.awssdk.auth.credentials.AwsCredentialsProvider;
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.s3.crt.S3CrtHttpConfiguration;
import software.amazon.awssdk.services.s3.crt.S3CrtRetryConfiguration;
import software.amazon.awssdk.services.s3.model.GetObjectRequest;
import software.amazon.awssdk.services.s3.model.PutObjectRequest;
import software.amazon.awssdk.utils.Validate;
Expand Down Expand Up @@ -161,6 +162,14 @@ public interface S3CrtAsyncClientBuilder extends SdkBuilder<S3CrtAsyncClientBuil
*/
S3CrtAsyncClientBuilder httpConfiguration(S3CrtHttpConfiguration configuration);

/**
* Sets the Retry configuration to use for this client.
*
* @param retryConfiguration The retry configurations to be used.
* @return The builder of the method chaining.
*/
S3CrtAsyncClientBuilder retryConfiguration(S3CrtRetryConfiguration retryConfiguration);

/**
* A convenience method that creates an instance of the {@link S3CrtHttpConfiguration} builder, avoiding the
* need to create one manually via {@link S3CrtHttpConfiguration#builder()}.
Expand All @@ -177,6 +186,25 @@ default S3CrtAsyncClientBuilder httpConfiguration(Consumer<S3CrtHttpConfiguratio
}


/**
* A convenience method that creates an instance of the {@link S3CrtRetryConfiguration} builder, avoiding the
* need to create one manually via {@link S3CrtRetryConfiguration#builder()}.
*
* @param retryConfigurationBuilder The retry config builder to use
* @return The builder of the method chaining.
* @see #retryConfiguration(S3CrtRetryConfiguration)
*/
default S3CrtAsyncClientBuilder retryConfiguration(Consumer<S3CrtRetryConfiguration.Builder> retryConfigurationBuilder) {
Validate.paramNotNull(retryConfigurationBuilder, "retryConfigurationBuilder");
return retryConfiguration(S3CrtRetryConfiguration.builder()
.applyMutation(retryConfigurationBuilder)
.build());
}





@Override
S3AsyncClient build();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
/*
* 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.services.s3.crt;

import java.util.Objects;
import software.amazon.awssdk.annotations.Immutable;
import software.amazon.awssdk.annotations.SdkPublicApi;
import software.amazon.awssdk.annotations.ThreadSafe;
import software.amazon.awssdk.services.s3.S3CrtAsyncClientBuilder;
import software.amazon.awssdk.utils.Validate;
import software.amazon.awssdk.utils.builder.CopyableBuilder;
import software.amazon.awssdk.utils.builder.ToCopyableBuilder;

/**
* Retry option configuration for AWS CRT-based S3 client.
*
* @see S3CrtAsyncClientBuilder#retryConfiguration
*/
@SdkPublicApi
@Immutable
@ThreadSafe
public final class S3CrtRetryConfiguration implements ToCopyableBuilder<S3CrtRetryConfiguration.Builder,
S3CrtRetryConfiguration> {
private final Integer numRetries;

private S3CrtRetryConfiguration(DefaultBuilder builder) {
Validate.notNull(builder.numRetries, "numRetries");
this.numRetries = builder.numRetries;
}

/**
* Creates a default builder for {@link S3CrtRetryConfiguration}.
*/
public static Builder builder() {
return new S3CrtRetryConfiguration.DefaultBuilder();
}

/**
* Retrieve the {@link S3CrtRetryConfiguration.Builder#numRetries(Integer)} configured on the builder.
*/
public Integer numRetries() {
return numRetries;
}

@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
S3CrtRetryConfiguration that = (S3CrtRetryConfiguration) o;
return Objects.equals(numRetries, that.numRetries);
}

@Override
public int hashCode() {
return numRetries != null ? numRetries.hashCode() : 0;
}

@Override
public Builder toBuilder() {
return new S3CrtRetryConfiguration.DefaultBuilder(this);
}

public interface Builder extends CopyableBuilder<S3CrtRetryConfiguration.Builder, S3CrtRetryConfiguration> {

/**
* Configure the maximum number of times that a single request should be retried.
* @param numRetries
* @return The builder of the method chaining.
*/
Comment thread
joviegas marked this conversation as resolved.
Builder numRetries(Integer numRetries);

}

private static final class DefaultBuilder implements Builder {
private Integer numRetries;

private DefaultBuilder() {
}

private DefaultBuilder(S3CrtRetryConfiguration crtRetryConfiguration) {
this.numRetries = crtRetryConfiguration.numRetries;
}

@Override
public Builder numRetries(Integer numRetries) {
this.numRetries = numRetries;
return this;
}

@Override
public S3CrtRetryConfiguration build() {
return new S3CrtRetryConfiguration(this);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -37,13 +37,16 @@
import software.amazon.awssdk.core.internal.util.ClassLoaderHelper;
import software.amazon.awssdk.core.retry.RetryPolicy;
import software.amazon.awssdk.core.signer.NoOpSigner;
import software.amazon.awssdk.crt.io.ExponentialBackoffRetryOptions;
import software.amazon.awssdk.crt.io.StandardRetryOptions;
import software.amazon.awssdk.http.SdkHttpExecutionAttributes;
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.s3.DelegatingS3AsyncClient;
import software.amazon.awssdk.services.s3.S3AsyncClient;
import software.amazon.awssdk.services.s3.S3Configuration;
import software.amazon.awssdk.services.s3.S3CrtAsyncClientBuilder;
import software.amazon.awssdk.services.s3.crt.S3CrtHttpConfiguration;
import software.amazon.awssdk.services.s3.crt.S3CrtRetryConfiguration;
import software.amazon.awssdk.services.s3.model.CopyObjectRequest;
import software.amazon.awssdk.services.s3.model.CopyObjectResponse;
import software.amazon.awssdk.services.s3.model.GetObjectRequest;
Expand Down Expand Up @@ -96,7 +99,7 @@ private static S3CrtAsyncHttpClient.Builder initializeS3CrtAsyncHttpClient(Defau
Validate.isPositiveOrNull(builder.targetThroughputInGbps, "targetThroughputInGbps");
Validate.isPositiveOrNull(builder.minimalPartSizeInBytes, "minimalPartSizeInBytes");

S3NativeClientConfiguration s3NativeClientConfiguration =
S3NativeClientConfiguration.Builder nativeClientBuilder =
S3NativeClientConfiguration.builder()
.checksumValidationEnabled(builder.checksumValidationEnabled)
.targetThroughputInGbps(builder.targetThroughputInGbps)
Expand All @@ -106,11 +109,16 @@ private static S3CrtAsyncHttpClient.Builder initializeS3CrtAsyncHttpClient(Defau
.endpointOverride(builder.endpointOverride)
.credentialsProvider(builder.credentialsProvider)
.readBufferSizeInBytes(builder.readBufferSizeInBytes)
.httpConfiguration(builder.httpConfiguration)
.build();
.httpConfiguration(builder.httpConfiguration);

if (builder.retryConfiguration != null) {
nativeClientBuilder.standardRetryOptions(
new StandardRetryOptions()
.withBackoffRetryOptions(new ExponentialBackoffRetryOptions()
Comment thread
joviegas marked this conversation as resolved.
.withMaxRetries(builder.retryConfiguration.numRetries())));
}
return S3CrtAsyncHttpClient.builder()
.s3ClientConfiguration(s3NativeClientConfiguration);
.s3ClientConfiguration(nativeClientBuilder.build());
}

public static final class DefaultS3CrtClientBuilder implements S3CrtAsyncClientBuilder {
Expand All @@ -123,6 +131,7 @@ public static final class DefaultS3CrtClientBuilder implements S3CrtAsyncClientB
private URI endpointOverride;
private Boolean checksumValidationEnabled;
private S3CrtHttpConfiguration httpConfiguration;
private S3CrtRetryConfiguration retryConfiguration;

public AwsCredentialsProvider credentialsProvider() {
return credentialsProvider;
Expand Down Expand Up @@ -206,6 +215,12 @@ public S3CrtAsyncClientBuilder httpConfiguration(S3CrtHttpConfiguration configur
return this;
}

@Override
public S3CrtAsyncClientBuilder retryConfiguration(S3CrtRetryConfiguration retryConfiguration) {
this.retryConfiguration = retryConfiguration;
return this;
}

@Override
public S3CrtAsyncClient build() {
return new DefaultS3CrtAsyncClient(this);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,9 @@ private S3CrtAsyncHttpClient(Builder builder) {
.withInitialReadWindowSize(initialWindowSize)
.withReadBackpressureEnabled(true);

if (s3NativeClientConfiguration.standardRetryOptions() != null) {
this.s3ClientOptions.withStandardRetryOptions(s3NativeClientConfiguration.standardRetryOptions());
}
Optional.ofNullable(s3NativeClientConfiguration.proxyOptions()).ifPresent(s3ClientOptions::withProxyOptions);
Optional.ofNullable(s3NativeClientConfiguration.connectionTimeout())
.map(Duration::toMillis)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import software.amazon.awssdk.crt.http.HttpMonitoringOptions;
import software.amazon.awssdk.crt.http.HttpProxyOptions;
import software.amazon.awssdk.crt.io.ClientBootstrap;
import software.amazon.awssdk.crt.io.StandardRetryOptions;
import software.amazon.awssdk.crt.io.TlsCipherPreference;
import software.amazon.awssdk.crt.io.TlsContext;
import software.amazon.awssdk.crt.io.TlsContextOptions;
Expand All @@ -43,6 +44,7 @@ public class S3NativeClientConfiguration implements SdkAutoCloseable {
private static final long DEFAULT_TARGET_THROUGHPUT_IN_GBPS = 10;

private final String signingRegion;
private final StandardRetryOptions standardRetryOptions;
private final ClientBootstrap clientBootstrap;
private final CrtCredentialsProviderAdapter credentialProviderAdapter;
private final CredentialsProvider credentialsProvider;
Expand Down Expand Up @@ -97,6 +99,7 @@ public S3NativeClientConfiguration(Builder builder) {
this.connectionTimeout = null;
this.httpMonitoringOptions = null;
}
this.standardRetryOptions = builder.standardRetryOptions;
}

public HttpMonitoringOptions httpMonitoringOptions() {
Expand Down Expand Up @@ -140,6 +143,10 @@ public int maxConcurrency() {
return maxConcurrency;
}

public StandardRetryOptions standardRetryOptions() {
return standardRetryOptions;
}

public URI endpointOverride() {
return endpointOverride;
}
Expand Down Expand Up @@ -169,6 +176,7 @@ public static final class Builder {
private URI endpointOverride;
private Boolean checksumValidationEnabled;
private S3CrtHttpConfiguration httpConfiguration;
private StandardRetryOptions standardRetryOptions;

private Builder() {
}
Expand Down Expand Up @@ -224,5 +232,10 @@ public Builder httpConfiguration(S3CrtHttpConfiguration httpConfiguration) {
this.httpConfiguration = httpConfiguration;
return this;
}

public Builder standardRetryOptions(StandardRetryOptions standardRetryOptions) {
this.standardRetryOptions = standardRetryOptions;
return this;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/*
* 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.services.s3.crt;

import nl.jqno.equalsverifier.EqualsVerifier;
import org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
import static org.assertj.core.api.Assertions.assertThatNullPointerException;


public class S3CrtRetryConfigurationTest {

@Test
void equalsHashcode() {
EqualsVerifier.forClass(S3CrtRetryConfiguration.class)
.withRedefinedSuperclass()
.verify();
}

@Test
void retryConfigurationWithNoMaxRetriesDefined(){
assertThatNullPointerException().isThrownBy(() ->S3CrtRetryConfiguration.builder().build())
.withMessage("numRetries");
}



}
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@
import org.mockito.Mockito;
import software.amazon.awssdk.core.interceptor.trait.HttpChecksum;
import software.amazon.awssdk.crt.http.HttpRequest;
import software.amazon.awssdk.crt.io.ExponentialBackoffRetryOptions;
import software.amazon.awssdk.crt.io.StandardRetryOptions;
import software.amazon.awssdk.crt.s3.ChecksumAlgorithm;
import software.amazon.awssdk.crt.s3.S3Client;
import software.amazon.awssdk.crt.s3.S3ClientOptions;
Expand Down Expand Up @@ -314,6 +316,9 @@ void build_shouldPassThroughParameters() {
S3NativeClientConfiguration.builder()
.maxConcurrency(100)
.signingRegion("us-west-2")
.standardRetryOptions(
new StandardRetryOptions()
.withBackoffRetryOptions(new ExponentialBackoffRetryOptions().withMaxRetries(7)))
.httpConfiguration(S3CrtHttpConfiguration.builder()
.connectionTimeout(Duration.ofSeconds(1))
.connectionHealthConfiguration(c -> c.minimumThroughputInBps(1024L)
Expand All @@ -325,6 +330,7 @@ void build_shouldPassThroughParameters() {
(S3CrtAsyncHttpClient) S3CrtAsyncHttpClient.builder().s3ClientConfiguration(configuration).build();
S3ClientOptions clientOptions = client.s3ClientOptions();
assertThat(clientOptions.getConnectTimeoutMs()).isEqualTo(1000);
assertThat(clientOptions.getStandardRetryOptions().getBackoffRetryOptions().getMaxRetries()).isEqualTo(7);
assertThat(clientOptions.getMaxConnections()).isEqualTo(100);
assertThat(clientOptions.getMonitoringOptions()).satisfies(options -> {
assertThat(options.getMinThroughputBytesPerSecond()).isEqualTo(1024);
Expand Down