in src/main/java/software/amazon/cloudformation/proxy/AmazonWebServicesClientProxy.java [352:427]
public ProgressEvent<ModelT, CallbackT> done(Callback<RequestT, ResponseT, ClientT, ModelT, CallbackT,
ProgressEvent<ModelT, CallbackT>> callback) {
//
// StdCallbackContext memoization wrappers for request, response, and
// stabilization
// lambdas. This ensures that we call demux as necessary.
//
final String callGraph = generator.callGraph(CallContext.this.callGraph, model, maker,
client.client(), context);
Delay delay = override.getDelay(callGraph, CallContext.this.delay);
Function<ModelT, RequestT> reqMaker = context.request(callGraph, maker);
BiFunction<RequestT, ProxyClient<ClientT>, ResponseT> resMaker = context.response(callGraph, caller);
if (waitFor != null) {
waitFor = context.stabilize(callGraph, waitFor);
}
int attempt = context.attempts(callGraph);
RequestT req = null;
ResponseT res = null;
ProgressEvent<ModelT, CallbackT> event = null;
Callback<? super RequestT, Exception, ClientT, ModelT, CallbackT,
ProgressEvent<ModelT, CallbackT>> exceptionHandler = getExceptionHandler(
AmazonWebServicesClientProxy.this::defaultHandler);
try {
for (;;) {
Instant now = Instant.now();
try {
req = req == null ? reqMaker.apply(model) : req;
res = res == null ? resMaker.apply(req, client) : res;
if (waitFor != null) {
if (waitFor.invoke(req, res, client, model, context)) {
event = callback.invoke(req, res, client, model, context);
}
} else {
event = callback.invoke(req, res, client, model, context);
}
} catch (BaseHandlerException e) {
throw e;
} catch (Exception e) {
event = exceptionHandler.invoke(req, e, client, model, context);
}
if (event != null) {
return event;
}
//
// The logic to wait is if next delay + 2 * time to run the operation sequence +
// 100ms
// is less than time remaining time to run inside Lambda then we locally wait
// else we bail out. Assuming 3 DAYS for a DB to restore, that would be total of
// 3 x 24 x 60 x 60 x 1000 ms, fits in 32 bit int.
//
Instant opTime = Instant.now();
long elapsed = ChronoUnit.MILLIS.between(now, opTime);
Duration next = delay.nextDelay(attempt++);
context.attempts(callGraph, attempt);
if (next == Duration.ZERO) {
return ProgressEvent.failed(model, context, HandlerErrorCode.NotStabilized,
"Exceeded attempts to wait");
}
event = AmazonWebServicesClientProxy.this.waitStrategy.await(elapsed, next, context, model);
if (event != null) {
return event;
}
}
} finally {
//
// only set request if response was successful. Otherwise we will remember the
// the original failed request in the callback. So when we fix and resume from
// the error with callback, we will replay the wrong one
//
if (res == null) {
context.evictRequestRecord(callGraph);
}
}
}