@@ -90,10 +90,12 @@ private CompletableFuture<Response<OutputT>> executeHttpRequest(SdkHttpFullReque
90
90
CompletableFuture <? extends SdkException > errorResponseFuture =
91
91
errorResponseHandler == null ? null : errorResponseHandler .prepare ();
92
92
93
+ CompletableFuture <Response <OutputT >> responseFuture = new CompletableFuture <>();
94
+
93
95
//FIXME(dongie): We need to be careful to only call responseHandler.prepare() exactly once per execute() call
94
96
//because it calls prepare() under the hood and we guarantee that we call that once per execution. It would be good
95
97
//to find a way to prevent multiple calls to prepare() within a single execution to only call prepare() once.
96
- ResponseHandler handler = new ResponseHandler (responseHandler .prepare (), errorResponseFuture );
98
+ ResponseHandler handler = new ResponseHandler (responseFuture , responseHandler .prepare (), errorResponseFuture );
97
99
98
100
SdkHttpContentPublisher requestProvider = context .requestProvider () == null
99
101
? new SimpleHttpContentPublisher (request )
@@ -112,7 +114,6 @@ private CompletableFuture<Response<OutputT>> executeHttpRequest(SdkHttpFullReque
112
114
113
115
CompletableFuture <Response <OutputT >> transformFuture = handler .prepare ();
114
116
115
- CompletableFuture <Response <OutputT >> responseFuture = new CompletableFuture <>();
116
117
TimeoutTracker timeoutTracker = setupAttemptTimer (responseFuture , context );
117
118
context .apiCallAttemptTimeoutTracker (timeoutTracker );
118
119
@@ -173,13 +174,16 @@ private TimeoutTracker setupAttemptTimer(CompletableFuture<Response<OutputT>> ex
173
174
*/
174
175
175
176
private class ResponseHandler implements TransformingAsyncResponseHandler <Response <OutputT >> {
177
+ private final CompletableFuture <Response <OutputT >> responseFuture ;
176
178
private final CompletableFuture <SdkHttpResponse > headersFuture = new CompletableFuture <>();
177
179
private final CompletableFuture <OutputT > transformFuture ;
178
180
private final CompletableFuture <? extends SdkException > errorTransformFuture ;
179
181
private volatile SdkHttpFullResponse response ;
180
182
181
- ResponseHandler (CompletableFuture <OutputT > transformFuture ,
183
+ ResponseHandler (CompletableFuture <Response <OutputT >> responseFuture ,
184
+ CompletableFuture <OutputT > transformFuture ,
182
185
CompletableFuture <? extends SdkException > errorTransformFuture ) {
186
+ this .responseFuture = responseFuture ;
183
187
this .transformFuture = transformFuture ;
184
188
this .errorTransformFuture = errorTransformFuture ;
185
189
}
@@ -199,18 +203,12 @@ public void onHeaders(SdkHttpResponse response) {
199
203
200
204
@ Override
201
205
public void onError (Throwable error ) {
202
- // If we already have the headers we've chosen one of the two
203
- // handlers so notify the correct handler. Otherwise, just complete
204
- // the future exceptionally
205
- if (response != null ) {
206
- if (response .isSuccessful ()) {
207
- responseHandler .onError (error );
208
- } else {
209
- errorResponseHandler .onError (error );
210
- }
211
- } else {
212
- headersFuture .completeExceptionally (error );
213
- }
206
+ // Note: We don't notify the wrapped handlers' onError here because
207
+ // we need context about retries; we only want to notify onError if
208
+ // we know that the request will be retried. Let the
209
+ // AsyncRetryableStage handle it.
210
+ responseFuture .completeExceptionally (error );
211
+ headersFuture .completeExceptionally (error );
214
212
}
215
213
216
214
@ Override
@@ -228,7 +226,11 @@ public CompletableFuture<Response<OutputT>> prepare() {
228
226
if (headers .isSuccessful ()) {
229
227
return transformFuture .thenApply (r -> Response .fromSuccess (r , response ));
230
228
} else {
231
- return errorTransformFuture .thenApply (e -> Response .fromFailure (e , response ));
229
+ if (errorTransformFuture != null ) {
230
+ return errorTransformFuture .thenApply (e -> Response .fromFailure (e , response ));
231
+ } else {
232
+ return CompletableFuture .completedFuture (Response .fromFailure (null , response ));
233
+ }
232
234
}
233
235
});
234
236
}
@@ -248,4 +250,4 @@ private static SdkHttpFullResponse toFullResponse(SdkHttpResponse response) {
248
250
response .statusText ().ifPresent (builder ::statusText );
249
251
return builder .build ();
250
252
}
251
- }
253
+ }
0 commit comments