Skip to content

Commit fc624b1

Browse files
committed
Pass retry token to call Context
Use `hook.context().get(CallContext.RETRY_TOKEN)` Closes #1124
1 parent 7e519b9 commit fc624b1

3 files changed

Lines changed: 34 additions & 15 deletions

File tree

client/client-core/src/main/java/software/amazon/smithy/java/client/core/CallContext.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
import software.amazon.smithy.java.context.Context;
1212
import software.amazon.smithy.java.endpoints.Endpoint;
1313
import software.amazon.smithy.java.endpoints.EndpointResolver;
14+
import software.amazon.smithy.java.retries.api.RetryToken;
1415

1516
/**
1617
* Context parameters made available to underlying transports like HTTP clients.
@@ -51,6 +52,17 @@ public final class CallContext {
5152
*/
5253
public static final Context.Key<Integer> RETRY_MAX = Context.key("Max retries");
5354

55+
/**
56+
* The opaque retry token for the current in-progress attempt, if a retry strategy is in use.
57+
*
58+
* <p>The token is acquired before the first attempt and refreshed after each retryable failure, so the value
59+
* observed by an interceptor is always the token in effect for the current attempt. It is {@code null} once the
60+
* call completes and the token is released.
61+
*
62+
* <p>This is a read-only value; modifying this value has no effect on a request.
63+
*/
64+
public static final Context.Key<RetryToken> RETRY_TOKEN = Context.key("Retry token");
65+
5466
/**
5567
* The idempotency token used with the call, if any.
5668
*

client/client-core/src/main/java/software/amazon/smithy/java/client/core/ClientCall.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,17 @@ final class ClientCall<I extends SerializableStruct, O extends SerializableStruc
109109
: null;
110110
}
111111

112+
/**
113+
* Set the retry token for the call, keeping {@link CallContext#RETRY_TOKEN} in sync so interceptors observe the
114+
* token in effect for the current attempt.
115+
*
116+
* @param retryToken the token to associate with the call, or {@code null} once the token is released.
117+
*/
118+
void setRetryToken(RetryToken retryToken) {
119+
this.retryToken = retryToken;
120+
this.context.put(CallContext.RETRY_TOKEN, retryToken);
121+
}
122+
112123
/**
113124
* Check if a retry is disallowed for this call.
114125
*

client/client-core/src/main/java/software/amazon/smithy/java/client/core/ClientPipeline.java

Lines changed: 11 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
import software.amazon.smithy.java.auth.api.identity.IdentityResult;
1616
import software.amazon.smithy.java.client.core.auth.scheme.AuthScheme;
1717
import software.amazon.smithy.java.client.core.auth.scheme.AuthSchemeOption;
18+
import software.amazon.smithy.java.client.core.auth.scheme.AuthSchemeResolver;
1819
import software.amazon.smithy.java.client.core.auth.scheme.AuthSchemeResolverParams;
1920
import software.amazon.smithy.java.client.core.interceptors.ClientInterceptor;
2021
import software.amazon.smithy.java.client.core.interceptors.InputHook;
@@ -136,20 +137,15 @@ private <I extends SerializableStruct, O extends SerializableStruct> O acquireRe
136137
ClientCall<I, O> call,
137138
RequestHook<I, O, RequestT> requestHook
138139
) {
139-
try {
140-
// 8. RetryStrategy: Invoke AcquireRetryToken.
141-
// Can potentially short-circuit the request.
142-
var result = call.retryStrategy.acquireInitialToken(new AcquireInitialTokenRequest(call.retryScope));
143-
call.retryToken = result.token();
144-
// Delay if the initial request is pre-emptively throttled.
145-
if (result.delay().toMillis() > 0) {
146-
sleep(result.delay());
147-
}
148-
return doSendOrRetry(call, requestHook);
149-
} catch (TokenAcquisitionFailedException e) {
150-
// Don't send the request if the circuit breaker prevents it.
151-
throw e;
140+
// 8. RetryStrategy: Invoke AcquireRetryToken.
141+
// Can potentially short-circuit the request.
142+
var result = call.retryStrategy.acquireInitialToken(new AcquireInitialTokenRequest(call.retryScope));
143+
call.setRetryToken(result.token());
144+
// Delay if the initial request is pre-emptively throttled.
145+
if (result.delay().toMillis() > 0) {
146+
sleep(result.delay());
152147
}
148+
return doSendOrRetry(call, requestHook);
153149
}
154150

155151
private <I extends SerializableStruct, O extends SerializableStruct> O doSendOrRetry(
@@ -459,7 +455,7 @@ private <I extends SerializableStruct, O extends SerializableStruct> O deseriali
459455

460456
// Clear out the retry token.
461457
var token = call.retryToken;
462-
call.retryToken = null;
458+
call.setRetryToken(null);
463459

464460
// 9.c.i If successful: RetryStrategy: Invoke RecordSuccess.
465461
if (error == null) {
@@ -509,7 +505,7 @@ private <I extends SerializableStruct, O extends SerializableStruct> O retry(
509505
Duration after
510506
) {
511507
// Associate the retry token with the call.
512-
call.retryToken = retryToken;
508+
call.setRetryToken(retryToken);
513509
// Adjust the current retry count on the context (e.g., protocols can use this to add retry headers).
514510
call.context.put(CallContext.RETRY_ATTEMPT, ++call.attemptCount);
515511

0 commit comments

Comments
 (0)