Package: cdk-stepfunctions-patterns
cdk-stepfunctions-patternscdk-stepfunctions-patternslibrary is a set ofAWS CDKconstructs that provide
resiliency patterns implementation for AWS Step Functions.All these patterns arecomposable, meaning that you can combine them together to create
quite complex state machines that are much easier to maintain and support than low-level
JSON definitions.Try / CatchTry / FinallyTry / Catch / FinallyRetry with backoff and jitterResilience lambda errors handlingValidation of proper resilience lambda errors handlingTry / Catch patternStep Functions supportTry / Catchpattern natively withTaskandParallelstates.TryTaskconstruct adds a high level abstraction that allows you to use Try / Catch pattern with any state or sequence of states.Example# Example automatically generated without compilation. See https://github.com/aws/jsii/issues/826importaws_cdk.aws_stepfunctionsassfnfromcdk_stepfunctions_patternsimportTryTask# ...sfn.StateMachine(self,"TryCatchStepMachine",definition=TryTask(self,"TryCatch",try_process=sfn.Pass(self,"A1").next(sfn.Pass(self,"B1")),catch_process=sfn.Pass(self,"catchHandler"),# optional configuration propertiescatch_props={"errors":["Lambda.AWSLambdaException"],"result_path":"$.ErrorDetails"}))Resulting StepFunctionTry / Finally patternIt is often useful to design state machine usingTry / Finallypattern. The idea is to have aFinalstate that has to be
executed regardless of successful or failed execution of theTrystate. There may be some temporal resource you want
to delete or notification to send.Step Functions do not provide a native way to implement that pattern but it can be done usingParallelstate andcatch allcatch
specification.TryTaskconstruct abstracts these implementation details and allows to express the pattern directly.Example# Example automatically generated without compilation. See https://github.com/aws/jsii/issues/826importaws_cdk.aws_stepfunctionsassfnfromcdk_stepfunctions_patternsimportTryTask# ...sfn.StateMachine(self,"TryFinallyStepMachine",definition=TryTask(self,"TryFinally",try_process=sfn.Pass(self,"A2").next(sfn.Pass(self,"B2")),finally_process=sfn.Pass(self,"finallyHandler"),# optional configuration propertiesfinally_error_path="$.FinallyErrorDetails"))Resulting StepFunctionTry / Catch / Finally patternThis is a combination of two previous patterns.TryTaskconstruct allows you to express rather complex
error handling logic in a very compact form.Example# Example automatically generated without compilation. See https://github.com/aws/jsii/issues/826importaws_cdk.aws_stepfunctionsassfnfromcdk_stepfunctions_patternsimportTryTask# ...sfn.StateMachine(self,"TryCatchFinallyStepMachine",definition=TryTask(self,"TryCatchFinalli",try_process=sfn.Pass(self,"A3").next(sfn.Pass(self,"B3")),catch_process=sfn.Pass(self,"catchHandler3"),finally_process=sfn.Pass(self,"finallyHandler3")))Resulting StepFunctionRetry with backoff and jitterOut of the box Step Functions retry implementation provides a way to configure backoff factor,
but there is no built in way to introduce jitter. As covered inExponential Backoff And JitterandWait and Retry with Jittered Back-offthis retry technique can be very helpful in high-load
scenarios.RetryWithJitterTaskconstruct provides a custom implementation of retry with backoff and
jitter that you can use directly in your state machines.Example# Example automatically generated without compilation. See https://github.com/aws/jsii/issues/826importaws_cdk.aws_stepfunctionsassfnfromcdk_stepfunctions_patternsimportRetryWithJitterTask# ...sfn.StateMachine(self,"RetryWithJitterStepMachine",definition=RetryWithJitterTask(self,"AWithJitter",try_process=sfn.Pass(self,"A4").next(sfn.Pass(self,"B4")),retry_props={"errors":["States.ALL"],"max_attempts":3}))Resulting StepFunctionResilience lambda errors handlingLambdaInvokeconstruct fromaws-stepfunctions-tasksmodule is probably one of the most used ones. Still, handling ofAWS Lambda service exceptionsis often overlooked.ResilientLambdaTaskis a drop-in replacement construct forLambdaInvokethat adds retry for the most common
transient errors:Lambda.ServiceExceptionLambda.AWSLambdaExceptionLambda.SdkClientExceptionLambda.TooManyRequestsExceptionExample# Example automatically generated without compilation. See https://github.com/aws/jsii/issues/826importaws_cdk.aws_lambdaaslambda_fromcdk_stepfunctions_patternsimportResilientLambdaTask# ...lambda_function=lambda_.Function(self,"LambdaFunction")calculate_jitter_task=ResilientLambdaTask(self,"InvokeLambda",lambda_function=lambda_function)That would result in the following state definition:"InvokeLambda":{"Type":"Task","Resource":"arn:aws:states:::lambda:invoke","Parameters":{"FunctionName":"<ARN of lambda function>"},"Retry":[{"ErrorEquals":["Lambda.ServiceException","Lambda.AWSLambdaException","Lambda.SdkClientException","Lambda.TooManyRequestsException"],"IntervalSeconds":2,"MaxAttempts":6,"BackoffRate":2}]}Validation of proper resilience lambda errors handlingIt is often a challenge to enforce consistent transient error handling across all state machines of a large
application. To help with that,cdk-stepfuctions-patternsprovides aCDK aspectto verify that all Lambda invocations correctly handle transient errors from AWS Lambda service.UseResilienceLambdaCheckeraspect as shown below.Example# Example automatically generated without compilation. See https://github.com/aws/jsii/issues/826importaws_cdk.coreascdkfromcdk_stepfunctions_patternsimportResilienceLambdaCheckerapp=cdk.App()# ...# validate compliance rulesapp.node.apply_aspect(ResilienceLambdaChecker())If there are some states in your application that do not retry transient errors or miss some recommended
error codes, there will be warning during CDK synthesize stage:PS C:\Dev\GitHub\cdk-stepfunctions-patterns> cdk synth --strict
[Warning at /StepFunctionsPatterns/A] No retry for AWS Lambda transient errors defined - consider using ResilientLambdaTask construct.
[Warning at /StepFunctionsPatterns/B] Missing retry for transient errors: Lambda.AWSLambdaException,Lambda.SdkClientException.