Skip to content

Commit a52e476

Browse files
authored
Merge branch 'master' into feature/master/s3mpu
2 parents e7292e2 + 5c8b665 commit a52e476

File tree

11 files changed

+174
-50
lines changed

11 files changed

+174
-50
lines changed
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"type": "feature",
3+
"category": "AWS SDK for Java v2",
4+
"contributor": "",
5+
"description": "Make Waiters use the new Backoff Strategy"
6+
}

codegen/src/main/java/software/amazon/awssdk/codegen/poet/waiters/BaseWaiterClassSpec.java

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -57,11 +57,10 @@
5757
import software.amazon.awssdk.codegen.poet.PoetUtils;
5858
import software.amazon.awssdk.core.ApiName;
5959
import software.amazon.awssdk.core.internal.waiters.WaiterAttribute;
60-
import software.amazon.awssdk.core.retry.backoff.BackoffStrategy;
61-
import software.amazon.awssdk.core.retry.backoff.FixedDelayBackoffStrategy;
6260
import software.amazon.awssdk.core.waiters.WaiterAcceptor;
6361
import software.amazon.awssdk.core.waiters.WaiterOverrideConfiguration;
6462
import software.amazon.awssdk.core.waiters.WaiterState;
63+
import software.amazon.awssdk.retries.api.BackoffStrategy;
6564
import software.amazon.awssdk.utils.AttributeMap;
6665
import software.amazon.awssdk.utils.SdkAutoCloseable;
6766

@@ -203,16 +202,17 @@ private MethodSpec waiterConfigInitializer(String waiterKey, WaiterDefinition wa
203202
+ ".orElse($L)",
204203
waiterDefinition.getMaxAttempts());
205204
configMethod.addStatement("$T backoffStrategy = optionalOverrideConfig."
206-
+ "flatMap(WaiterOverrideConfiguration::backoffStrategy).orElse($T.create($T.ofSeconds($L)))",
205+
+ "flatMap(WaiterOverrideConfiguration::backoffStrategyV2)"
206+
+ ".orElse($T.fixedDelayWithoutJitter($T.ofSeconds($L)))",
207+
BackoffStrategy.class,
207208
BackoffStrategy.class,
208-
FixedDelayBackoffStrategy.class,
209209
Duration.class,
210210
waiterDefinition.getDelay());
211211
configMethod.addStatement("$T waitTimeout = optionalOverrideConfig.flatMap(WaiterOverrideConfiguration::waitTimeout)"
212212
+ ".orElse(null)",
213213
Duration.class);
214214

215-
configMethod.addStatement("return WaiterOverrideConfiguration.builder().maxAttempts(maxAttempts).backoffStrategy"
215+
configMethod.addStatement("return WaiterOverrideConfiguration.builder().maxAttempts(maxAttempts).backoffStrategyV2"
216216
+ "(backoffStrategy).waitTimeout(waitTimeout).build()");
217217
return configMethod.build();
218218
}

codegen/src/test/resources/software/amazon/awssdk/codegen/poet/waiters/query-async-waiter-class.java

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,12 @@
1616
import software.amazon.awssdk.awscore.exception.AwsServiceException;
1717
import software.amazon.awssdk.core.ApiName;
1818
import software.amazon.awssdk.core.internal.waiters.WaiterAttribute;
19-
import software.amazon.awssdk.core.retry.backoff.BackoffStrategy;
20-
import software.amazon.awssdk.core.retry.backoff.FixedDelayBackoffStrategy;
2119
import software.amazon.awssdk.core.waiters.AsyncWaiter;
2220
import software.amazon.awssdk.core.waiters.WaiterAcceptor;
2321
import software.amazon.awssdk.core.waiters.WaiterOverrideConfiguration;
2422
import software.amazon.awssdk.core.waiters.WaiterResponse;
2523
import software.amazon.awssdk.core.waiters.WaiterState;
24+
import software.amazon.awssdk.retries.api.BackoffStrategy;
2625
import software.amazon.awssdk.services.query.QueryAsyncClient;
2726
import software.amazon.awssdk.services.query.jmespath.internal.JmesPathRuntime;
2827
import software.amazon.awssdk.services.query.model.APostOperationRequest;
@@ -108,10 +107,10 @@ private static List<WaiterAcceptor<? super APostOperationResponse>> postOperatio
108107
private static WaiterOverrideConfiguration postOperationSuccessWaiterConfig(WaiterOverrideConfiguration overrideConfig) {
109108
Optional<WaiterOverrideConfiguration> optionalOverrideConfig = Optional.ofNullable(overrideConfig);
110109
int maxAttempts = optionalOverrideConfig.flatMap(WaiterOverrideConfiguration::maxAttempts).orElse(40);
111-
BackoffStrategy backoffStrategy = optionalOverrideConfig.flatMap(WaiterOverrideConfiguration::backoffStrategy).orElse(
112-
FixedDelayBackoffStrategy.create(Duration.ofSeconds(1)));
110+
BackoffStrategy backoffStrategy = optionalOverrideConfig.flatMap(WaiterOverrideConfiguration::backoffStrategyV2).orElse(
111+
BackoffStrategy.fixedDelayWithoutJitter(Duration.ofSeconds(1)));
113112
Duration waitTimeout = optionalOverrideConfig.flatMap(WaiterOverrideConfiguration::waitTimeout).orElse(null);
114-
return WaiterOverrideConfiguration.builder().maxAttempts(maxAttempts).backoffStrategy(backoffStrategy)
113+
return WaiterOverrideConfiguration.builder().maxAttempts(maxAttempts).backoffStrategyV2(backoffStrategy)
115114
.waitTimeout(waitTimeout).build();
116115
}
117116

codegen/src/test/resources/software/amazon/awssdk/codegen/poet/waiters/query-sync-waiter-class.java

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,12 @@
1313
import software.amazon.awssdk.awscore.exception.AwsServiceException;
1414
import software.amazon.awssdk.core.ApiName;
1515
import software.amazon.awssdk.core.internal.waiters.WaiterAttribute;
16-
import software.amazon.awssdk.core.retry.backoff.BackoffStrategy;
17-
import software.amazon.awssdk.core.retry.backoff.FixedDelayBackoffStrategy;
1816
import software.amazon.awssdk.core.waiters.Waiter;
1917
import software.amazon.awssdk.core.waiters.WaiterAcceptor;
2018
import software.amazon.awssdk.core.waiters.WaiterOverrideConfiguration;
2119
import software.amazon.awssdk.core.waiters.WaiterResponse;
2220
import software.amazon.awssdk.core.waiters.WaiterState;
21+
import software.amazon.awssdk.retries.api.BackoffStrategy;
2322
import software.amazon.awssdk.services.query.QueryClient;
2423
import software.amazon.awssdk.services.query.jmespath.internal.JmesPathRuntime;
2524
import software.amazon.awssdk.services.query.model.APostOperationRequest;
@@ -90,10 +89,10 @@ private static List<WaiterAcceptor<? super APostOperationResponse>> postOperatio
9089
private static WaiterOverrideConfiguration postOperationSuccessWaiterConfig(WaiterOverrideConfiguration overrideConfig) {
9190
Optional<WaiterOverrideConfiguration> optionalOverrideConfig = Optional.ofNullable(overrideConfig);
9291
int maxAttempts = optionalOverrideConfig.flatMap(WaiterOverrideConfiguration::maxAttempts).orElse(40);
93-
BackoffStrategy backoffStrategy = optionalOverrideConfig.flatMap(WaiterOverrideConfiguration::backoffStrategy).orElse(
94-
FixedDelayBackoffStrategy.create(Duration.ofSeconds(1)));
92+
BackoffStrategy backoffStrategy = optionalOverrideConfig.flatMap(WaiterOverrideConfiguration::backoffStrategyV2).orElse(
93+
BackoffStrategy.fixedDelayWithoutJitter(Duration.ofSeconds(1)));
9594
Duration waitTimeout = optionalOverrideConfig.flatMap(WaiterOverrideConfiguration::waitTimeout).orElse(null);
96-
return WaiterOverrideConfiguration.builder().maxAttempts(maxAttempts).backoffStrategy(backoffStrategy)
95+
return WaiterOverrideConfiguration.builder().maxAttempts(maxAttempts).backoffStrategyV2(backoffStrategy)
9796
.waitTimeout(waitTimeout).build();
9897
}
9998

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
/*
2+
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License").
5+
* You may not use this file except in compliance with the License.
6+
* A copy of the License is located at
7+
*
8+
* http://aws.amazon.com/apache2.0
9+
*
10+
* or in the "license" file accompanying this file. This file is distributed
11+
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
12+
* express or implied. See the License for the specific language governing
13+
* permissions and limitations under the License.
14+
*/
15+
16+
package software.amazon.awssdk.core.internal.waiters;
17+
18+
import java.time.Duration;
19+
import java.util.Objects;
20+
import software.amazon.awssdk.annotations.SdkInternalApi;
21+
import software.amazon.awssdk.core.retry.RetryPolicyContext;
22+
import software.amazon.awssdk.retries.api.BackoffStrategy;
23+
24+
@SdkInternalApi
25+
public class LegacyToNonLegacyAdapter implements BackoffStrategy {
26+
private final software.amazon.awssdk.core.retry.backoff.BackoffStrategy adaptee;
27+
28+
public LegacyToNonLegacyAdapter(software.amazon.awssdk.core.retry.backoff.BackoffStrategy adaptee) {
29+
this.adaptee = Objects.requireNonNull(adaptee);
30+
}
31+
32+
@Override
33+
public Duration computeDelay(int attempt) {
34+
return adaptee.computeDelayBeforeNextRetry(RetryPolicyContext.builder()
35+
.retriesAttempted(attempt - 2)
36+
.build());
37+
}
38+
39+
public software.amazon.awssdk.core.retry.backoff.BackoffStrategy adaptee() {
40+
return adaptee;
41+
}
42+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
/*
2+
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License").
5+
* You may not use this file except in compliance with the License.
6+
* A copy of the License is located at
7+
*
8+
* http://aws.amazon.com/apache2.0
9+
*
10+
* or in the "license" file accompanying this file. This file is distributed
11+
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
12+
* express or implied. See the License for the specific language governing
13+
* permissions and limitations under the License.
14+
*/
15+
16+
package software.amazon.awssdk.core.internal.waiters;
17+
18+
import java.time.Duration;
19+
import java.util.Objects;
20+
import software.amazon.awssdk.annotations.SdkInternalApi;
21+
import software.amazon.awssdk.core.retry.RetryPolicyContext;
22+
import software.amazon.awssdk.retries.api.BackoffStrategy;
23+
24+
@SdkInternalApi
25+
public class NonLegacyToLegacyAdapter implements software.amazon.awssdk.core.retry.backoff.BackoffStrategy {
26+
private final BackoffStrategy adaptee;
27+
28+
public NonLegacyToLegacyAdapter(BackoffStrategy adaptee) {
29+
this.adaptee = Objects.requireNonNull(adaptee);
30+
}
31+
32+
@Override
33+
public Duration computeDelayBeforeNextRetry(RetryPolicyContext context) {
34+
return adaptee.computeDelay(context.retriesAttempted());
35+
}
36+
}

core/sdk-core/src/main/java/software/amazon/awssdk/core/internal/waiters/WaiterConfiguration.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,25 +18,25 @@
1818
import java.time.Duration;
1919
import java.util.Optional;
2020
import software.amazon.awssdk.annotations.SdkInternalApi;
21-
import software.amazon.awssdk.core.retry.backoff.BackoffStrategy;
22-
import software.amazon.awssdk.core.retry.backoff.FixedDelayBackoffStrategy;
2321
import software.amazon.awssdk.core.waiters.WaiterOverrideConfiguration;
22+
import software.amazon.awssdk.retries.api.BackoffStrategy;
2423

2524
/**
2625
* Internal waiter configuration class that provides default values if not overridden.
2726
*/
2827
@SdkInternalApi
2928
public final class WaiterConfiguration {
3029
private static final int DEFAULT_MAX_ATTEMPTS = 3;
31-
private static final BackoffStrategy DEFAULT_BACKOFF_STRATEGY = FixedDelayBackoffStrategy.create(Duration.ofSeconds(5));
30+
private static final BackoffStrategy DEFAULT_BACKOFF_STRATEGY =
31+
BackoffStrategy.fixedDelayWithoutJitter(Duration.ofSeconds(5));
3232
private final Integer maxAttempts;
3333
private final BackoffStrategy backoffStrategy;
3434
private final Duration waitTimeout;
3535

3636
public WaiterConfiguration(WaiterOverrideConfiguration overrideConfiguration) {
3737
Optional<WaiterOverrideConfiguration> configuration = Optional.ofNullable(overrideConfiguration);
3838
this.backoffStrategy =
39-
configuration.flatMap(WaiterOverrideConfiguration::backoffStrategy).orElse(DEFAULT_BACKOFF_STRATEGY);
39+
configuration.flatMap(WaiterOverrideConfiguration::backoffStrategyV2).orElse(DEFAULT_BACKOFF_STRATEGY);
4040
this.waitTimeout = configuration.flatMap(WaiterOverrideConfiguration::waitTimeout).orElse(null);
4141
this.maxAttempts = configuration.flatMap(WaiterOverrideConfiguration::maxAttempts).orElse(DEFAULT_MAX_ATTEMPTS);
4242
}

core/sdk-core/src/main/java/software/amazon/awssdk/core/internal/waiters/WaiterExecutorHelper.java

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,9 @@
2020
import java.util.Optional;
2121
import software.amazon.awssdk.annotations.SdkInternalApi;
2222
import software.amazon.awssdk.core.exception.SdkClientException;
23-
import software.amazon.awssdk.core.retry.RetryPolicyContext;
24-
import software.amazon.awssdk.core.retry.backoff.BackoffStrategy;
2523
import software.amazon.awssdk.core.waiters.WaiterAcceptor;
2624
import software.amazon.awssdk.core.waiters.WaiterResponse;
25+
import software.amazon.awssdk.retries.api.BackoffStrategy;
2726
import software.amazon.awssdk.utils.Either;
2827

2928
/**
@@ -57,9 +56,13 @@ public Optional<WaiterAcceptor<? super T>> firstWaiterAcceptorIfMatched(Either<T
5756
}
5857

5958
public long computeNextDelayInMills(int attemptNumber) {
60-
return backoffStrategy.computeDelayBeforeNextRetry(RetryPolicyContext.builder()
61-
.retriesAttempted(attemptNumber)
62-
.build())
59+
// This API used originally the legacy BackoffStrategies.
60+
// The new retries-API backoff strategies work with attempts whereas
61+
// the legacies backoff strategies work with retries, attempts is
62+
// equals to retries + 1. Added to that, the new backoff strategies
63+
// expect the attempt count to be incremented before computing the delay,
64+
// therefore we add here + 2 to account for these differences.
65+
return backoffStrategy.computeDelay(attemptNumber + 2)
6366
.toMillis();
6467
}
6568

core/sdk-core/src/main/java/software/amazon/awssdk/core/waiters/WaiterOverrideConfiguration.java

Lines changed: 54 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -19,15 +19,17 @@
1919
import java.util.Objects;
2020
import java.util.Optional;
2121
import software.amazon.awssdk.annotations.SdkPublicApi;
22-
import software.amazon.awssdk.core.retry.backoff.BackoffStrategy;
22+
import software.amazon.awssdk.core.internal.waiters.LegacyToNonLegacyAdapter;
23+
import software.amazon.awssdk.core.internal.waiters.NonLegacyToLegacyAdapter;
24+
import software.amazon.awssdk.retries.api.BackoffStrategy;
2325
import software.amazon.awssdk.utils.ToString;
2426
import software.amazon.awssdk.utils.Validate;
2527
import software.amazon.awssdk.utils.builder.CopyableBuilder;
2628
import software.amazon.awssdk.utils.builder.ToCopyableBuilder;
2729

2830
/**
29-
* Configuration values for the {@link Waiter}. All values are optional, and the default values will be used
30-
* if they are not specified.
31+
* Configuration values for the {@link Waiter}. All values are optional, and the default values will be used if they are not
32+
* specified.
3133
*/
3234
@SdkPublicApi
3335
public final class WaiterOverrideConfiguration implements ToCopyableBuilder<WaiterOverrideConfiguration.Builder,
@@ -39,8 +41,16 @@ public final class WaiterOverrideConfiguration implements ToCopyableBuilder<Wait
3941

4042
public WaiterOverrideConfiguration(Builder builder) {
4143
this.maxAttempts = Validate.isPositiveOrNull(builder.maxAttempts, "maxAttempts");
42-
this.backoffStrategy = builder.backoffStrategy;
4344
this.waitTimeout = Validate.isPositiveOrNull(builder.waitTimeout, "waitTimeout");
45+
Validate.mutuallyExclusive("Only one of backoffStrategy or backoffStrategyV2 may be used, but both where defined",
46+
builder.backoffStrategy, builder.backoffStrategyV2);
47+
if (builder.backoffStrategyV2 != null) {
48+
this.backoffStrategy = builder.backoffStrategyV2;
49+
} else if (builder.backoffStrategy != null) {
50+
this.backoffStrategy = new LegacyToNonLegacyAdapter(builder.backoffStrategy);
51+
} else {
52+
this.backoffStrategy = null;
53+
}
4454
}
4555

4656
public static Builder builder() {
@@ -54,16 +64,30 @@ public Optional<Integer> maxAttempts() {
5464
return Optional.ofNullable(maxAttempts);
5565
}
5666

67+
/**
68+
* @return the optional {@link software.amazon.awssdk.core.retry.backoff.BackoffStrategy} that should be used when polling the
69+
* resource
70+
* @deprecated Use instead {@link #backoffStrategyV2()}
71+
*/
72+
public Optional<software.amazon.awssdk.core.retry.backoff.BackoffStrategy> backoffStrategy() {
73+
if (backoffStrategy == null) {
74+
return Optional.empty();
75+
}
76+
if (backoffStrategy instanceof LegacyToNonLegacyAdapter) {
77+
return Optional.of(((LegacyToNonLegacyAdapter) backoffStrategy).adaptee());
78+
}
79+
return Optional.of(new NonLegacyToLegacyAdapter(backoffStrategy));
80+
}
81+
5782
/**
5883
* @return the optional {@link BackoffStrategy} that should be used when polling the resource
5984
*/
60-
public Optional<BackoffStrategy> backoffStrategy() {
85+
public Optional<BackoffStrategy> backoffStrategyV2() {
6186
return Optional.ofNullable(backoffStrategy);
6287
}
6388

6489
/**
6590
* @return the optional amount of time to wait that should be used when polling the resource
66-
*
6791
*/
6892
public Optional<Duration> waitTimeout() {
6993
return Optional.ofNullable(waitTimeout);
@@ -72,7 +96,8 @@ public Optional<Duration> waitTimeout() {
7296
@Override
7397
public Builder toBuilder() {
7498
return new Builder().maxAttempts(maxAttempts)
75-
.backoffStrategy(backoffStrategy)
99+
.backoffStrategyV2(backoffStrategy)
100+
.backoffStrategy(null)
76101
.waitTimeout(waitTimeout);
77102
}
78103

@@ -115,24 +140,39 @@ public String toString() {
115140

116141
public static final class Builder implements CopyableBuilder<WaiterOverrideConfiguration.Builder,
117142
WaiterOverrideConfiguration> {
118-
private BackoffStrategy backoffStrategy;
119143
private Integer maxAttempts;
120144
private Duration waitTimeout;
145+
private software.amazon.awssdk.core.retry.backoff.BackoffStrategy backoffStrategy;
146+
private BackoffStrategy backoffStrategyV2;
121147

122148
private Builder() {
123149
}
124150

125151
/**
126-
* Define the {@link BackoffStrategy} that computes the delay before the next retry request.
152+
* Define the {@link software.amazon.awssdk.core.retry.backoff.BackoffStrategy} that computes the delay between resource
153+
* polling. Only one of {@link Builder#backoffStrategy()} and {@link Builder#backoffStrategyV2()} may be defined.
127154
*
128155
* @param backoffStrategy The new backoffStrategy value.
129156
* @return This object for method chaining.
157+
* @deprecated Use instead {@link #backoffStrategyV2(BackoffStrategy)}
130158
*/
131-
public Builder backoffStrategy(BackoffStrategy backoffStrategy) {
159+
public Builder backoffStrategy(software.amazon.awssdk.core.retry.backoff.BackoffStrategy backoffStrategy) {
132160
this.backoffStrategy = backoffStrategy;
133161
return this;
134162
}
135163

164+
/**
165+
* Define the {@link BackoffStrategy} that computes the delay between resource polling. Only one of
166+
* {@link Builder#backoffStrategy()} and {@link Builder#backoffStrategyV2()} may be defined.
167+
*
168+
* @param backoffStrategy The new backoffStrategy value.
169+
* @return This object for method chaining.
170+
*/
171+
public Builder backoffStrategyV2(BackoffStrategy backoffStrategy) {
172+
this.backoffStrategyV2 = backoffStrategy;
173+
return this;
174+
}
175+
136176
/**
137177
* Define the maximum number of attempts to try before transitioning the waiter to a failure state.
138178
*
@@ -145,10 +185,9 @@ public Builder maxAttempts(Integer maxAttempts) {
145185
}
146186

147187
/**
148-
* Define the amount of time to wait for the resource to transition to the desired state before
149-
* timing out. This wait timeout doesn't have strict guarantees on how quickly a request is aborted
150-
* when the timeout is breached. The request can timeout early if it is determined that the next
151-
* retry will breach the max wait time. It's disabled by default.
188+
* Define the amount of time to wait for the resource to transition to the desired state before timing out. This wait
189+
* timeout doesn't have strict guarantees on how quickly a request is aborted when the timeout is breached. The request
190+
* can timeout early if it is determined that the next retry will breach the max wait time. It's disabled by default.
152191
*
153192
* @param waitTimeout The new waitTimeout value.
154193
* @return This object for method chaining.
@@ -163,4 +202,5 @@ public WaiterOverrideConfiguration build() {
163202
return new WaiterOverrideConfiguration(this);
164203
}
165204
}
205+
166206
}

0 commit comments

Comments
 (0)