1
15
16 package software.amazon.awssdk.core.internal.http.pipeline.stages;
17
18 import java.io.IOException;
19 import java.time.Duration;
20 import java.util.concurrent.TimeUnit;
21 import software.amazon.awssdk.annotations.SdkInternalApi;
22 import software.amazon.awssdk.core.Response;
23 import software.amazon.awssdk.core.exception.SdkException;
24 import software.amazon.awssdk.core.internal.http.HttpClientDependencies;
25 import software.amazon.awssdk.core.internal.http.RequestExecutionContext;
26 import software.amazon.awssdk.core.internal.http.pipeline.RequestPipeline;
27 import software.amazon.awssdk.core.internal.http.pipeline.RequestToResponsePipeline;
28 import software.amazon.awssdk.core.internal.http.pipeline.stages.utils.RetryableStageHelper;
29 import software.amazon.awssdk.http.SdkHttpFullRequest;
30
31
34 @SdkInternalApi
35 public final class RetryableStage<OutputT> implements RequestToResponsePipeline<OutputT> {
36 private final RequestPipeline<SdkHttpFullRequest, Response<OutputT>> requestPipeline;
37 private final HttpClientDependencies dependencies;
38
39 public RetryableStage(HttpClientDependencies dependencies,
40 RequestPipeline<SdkHttpFullRequest, Response<OutputT>> requestPipeline) {
41 this.dependencies = dependencies;
42 this.requestPipeline = requestPipeline;
43 }
44
45 public Response<OutputT> execute(SdkHttpFullRequest request, RequestExecutionContext context) throws Exception {
46 RetryableStageHelper retryableStageHelper = new RetryableStageHelper(request, context, dependencies);
47
48 while (true) {
49 retryableStageHelper.startingAttempt();
50
51 if (!retryableStageHelper.retryPolicyAllowsRetry()) {
52 throw retryableStageHelper.retryPolicyDisallowedRetryException();
53 }
54
55 Duration backoffDelay = retryableStageHelper.getBackoffDelay();
56 if (!backoffDelay.isZero()) {
57 retryableStageHelper.logBackingOff(backoffDelay);
58 TimeUnit.MILLISECONDS.sleep(backoffDelay.toMillis());
59 }
60
61 Response<OutputT> response;
62 try {
63 retryableStageHelper.logSendingRequest();
64 response = requestPipeline.execute(retryableStageHelper.requestToSend(), context);
65 } catch (SdkException | IOException e) {
66 retryableStageHelper.setLastException(e);
67 continue;
68 }
69
70 retryableStageHelper.setLastResponse(response.httpResponse());
71
72 if (!response.isSuccess()) {
73 retryableStageHelper.adjustClockIfClockSkew(response);
74 retryableStageHelper.setLastException(response.exception());
75 continue;
76 }
77
78 retryableStageHelper.attemptSucceeded();
79 return response;
80 }
81 }
82 }
83