Skip to content

Commit cee339a

Browse files
authored
Add Amazon exception map to CFN exception for throttling issues (#374)
* Add Amazon exception map to CFN exception for throttling issues * Fix unit tests for Wrapper class * Use RetryUtils for throttling pending
1 parent 850d993 commit cee339a

File tree

2 files changed

+46
-3
lines changed

2 files changed

+46
-3
lines changed

src/main/java/software/amazon/cloudformation/AbstractWrapper.java

+11-3
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
package software.amazon.cloudformation;
1616

1717
import com.amazonaws.AmazonServiceException;
18+
import com.amazonaws.retry.RetryUtils;
1819
import com.fasterxml.jackson.core.type.TypeReference;
1920
import com.fasterxml.jackson.databind.exc.MismatchedInputException;
2021
import com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException;
@@ -373,9 +374,16 @@ private void logUnhandledError(final String errorDescription,
373374
logUnhandledError(e.getMessage(), request, e);
374375
return ProgressEvent.defaultFailureHandler(e, e.getErrorCode());
375376
} catch (final AmazonServiceException | AwsServiceException e) {
376-
publishExceptionMetric(request.getAction(), e, HandlerErrorCode.GeneralServiceException);
377-
logUnhandledError("A downstream service error occurred", request, e);
378-
return ProgressEvent.defaultFailureHandler(e, HandlerErrorCode.GeneralServiceException);
377+
if ((e instanceof AwsServiceException && ((AwsServiceException) e).isThrottlingException()) ||
378+
(e instanceof AmazonServiceException && RetryUtils.isThrottlingException((AmazonServiceException) e))) {
379+
this.log(String.format("%s [%s] call throttled by downstream service", request.getResourceType(), request.getAction()));
380+
publishExceptionMetric(request.getAction(), e, HandlerErrorCode.Throttling);
381+
return ProgressEvent.defaultFailureHandler(e, HandlerErrorCode.Throttling);
382+
} else {
383+
publishExceptionMetric(request.getAction(), e, HandlerErrorCode.GeneralServiceException);
384+
logUnhandledError("A downstream service error occurred", request, e);
385+
return ProgressEvent.defaultFailureHandler(e, HandlerErrorCode.GeneralServiceException);
386+
}
379387
} catch (final Throwable e) {
380388
publishExceptionMetric(request.getAction(), e, HandlerErrorCode.InternalFailure);
381389
logUnhandledError("An unknown error occurred ", request, e);

src/test/java/software/amazon/cloudformation/WrapperTest.java

+35
Original file line numberDiff line numberDiff line change
@@ -785,6 +785,41 @@ public void invokeHandler_throwsSDK2ServiceException_returnsServiceException() t
785785
}
786786
}
787787

788+
@Test
789+
public void invokeHandler_throwsThrottlingException_returnsCFNThrottlingException() throws IOException {
790+
AmazonServiceException exception = new AmazonServiceException("Rate Exceed ...");
791+
exception.setErrorCode("Throttling");
792+
wrapper.setInvokeHandlerException(exception);
793+
794+
wrapper.setTransformResponse(resourceHandlerRequest);
795+
796+
try (final InputStream in = loadRequestStream("create.request.json");
797+
final OutputStream out = new ByteArrayOutputStream()) {
798+
799+
wrapper.processRequest(in, out);
800+
801+
// verify initialiseRuntime was called and initialised dependencies
802+
verifyInitialiseRuntime();
803+
804+
// all metrics should be published, once for a single invocation
805+
verify(providerMetricsPublisher, times(1)).publishInvocationMetric(any(Instant.class), eq(Action.CREATE));
806+
verify(providerMetricsPublisher, times(1)).publishDurationMetric(any(Instant.class), eq(Action.CREATE), anyLong());
807+
808+
// failure metric should be published
809+
verify(providerMetricsPublisher, times(1)).publishExceptionMetric(any(Instant.class), any(),
810+
any(AmazonServiceException.class), any(HandlerErrorCode.class));
811+
812+
// verify that model validation occurred for CREATE/UPDATE/DELETE
813+
verify(validator).validateObject(any(JSONObject.class), any(JSONObject.class));
814+
815+
// verify output response
816+
verifyHandlerResponse(out,
817+
ProgressEvent.<TestModel, TestContext>builder().errorCode(HandlerErrorCode.Throttling)
818+
.status(OperationStatus.FAILED)
819+
.message("some error (Service: null; Status Code: 0; Error Code: null; Request ID: null)").build());
820+
}
821+
}
822+
788823
@Test
789824
public void invokeHandler_throwsResourceAlreadyExistsException_returnsAlreadyExists() throws IOException {
790825
// exceptions are caught consistently by LambdaWrapper

0 commit comments

Comments
 (0)