Skip to content

Lambda Async Failure Destination

Level: Error

Initial version: 0.1.8

cfn-lint: ES1007

tflint: aws_lambda_event_invoke_config_async_on_failure

Several AWS services, such as Amazon S3, Amazon SNS, or Amazon EventBridge, invoke Lambda functions asynchronously to process events. When you invoke a function asynchronously, you don't wait for a response from the function code. You hand off the event to Lambda and Lambda handles the rest.

When an asynchronous calls fail, they should be captured and retried whenever possible. For this purpose, you can set a destination where Lambda will send events for successful or failed invocations.

Matching function name between resources

This rule works by comparing Lambda Permission resources with Lambda Event Invoke Config resources. For this rule to work correctly, you must set the function name on both resources in the exact same way.

For example, in CloudFormation, if you use the Fn::Ref intrinsic function to refer to your Lambda function on both resources, this rule will work normally. If you use Fn::Ref on one, and Fn::Join on another, this rule will not work.

Here are some examples of valid implementation in CloudFormation:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
Resources:
  Permission:
    Type: AWS::Lambda::Permission
    Properties:
      # Other properties omitted
      FunctionName: !Ref MyFunction

  EventInvokeConfig:
    Type: AWS::Lambda::EventInvokeConfig
    Properties:
      # Other properties omitted
      FunctionName: !Ref MyFunction
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
Resources:
  Permission:
    Type: AWS::Lambda::Permission
    Properties:
      # Other properties omitted
      FunctionName: !Sub "arn:${AWS::Partition}:lambda:${AWS::Region}:${AWS::AccountId}:function:${MyFunction}"

  EventInvokeConfig:
    Type: AWS::Lambda::EventInvokeConfig
    Properties:
      # Other properties omitted
      FunctionName: !Sub "arn:${AWS::Partition}:lambda:${AWS::Region}:${AWS::AccountId}:function:${MyFunction}"
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
Resources:
  Permission:
    Type: AWS::Lambda::Permission
    Properties:
      # Other properties omitted
      FunctionName: my-lambda-function

  EventInvokeConfig:
    Type: AWS::Lambda::EventInvokeConfig
    Properties:
      # Other properties omitted
      FunctionName: my-lambda-function

By comparison, this implementation will return an error:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
Resources:
  Permission:
    Type: AWS::Lambda::Permission
    Properties:
      # Other properties omitted
      FunctionName: !Ref MyFunction

  EventInvokeConfig:
    Type: AWS::Lambda::EventInvokeConfig
    Properties:
      # Other properties omitted
      FunctionName: my-lambda-function
Disabled for Terraform

This rule is disabled for Terraform, as the current linter only support static values in expressions. See this issue for more information.

Implementations

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
import { Code, Function, Runtime } from '@aws-cdk/aws-lambda';
import { SnsEventSource } from '@aws-cdk/aws-lambda-event-sources';
import { SqsDestination } from '@aws-cdk/aws-lambda-destinations';
import { Topic } from '@aws-cdk/aws-sns';

export class MyStack extends cdk.Stack {
  constructor(scope: cdk.Construct, id: string, props?: cdk.StackProps) {
    super(scope, id, props);

    const myTopic = new Topic(
      scope, 'MyTopic',
    );

    const myDLQ = new Queue(
      scope, 'MyDLQ',
    );

    const myFunction = new Function(
      scope, 'MyFunction',
      {
        code: Code.fromAsset('src/hello/'),
        handler: 'main.handler',
        runtime: Runtime.PYTHON_3_8,

        onFailure: new SqsDestination(myDLQ),
      }
    );

    // SNS will trigger the function asynchronously
    myFunction.addEventSource(new SnsEventSource(myTopic));


  }
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
{
  "Resources": {
    "SNSFunction": {
      "Type": "AWS::Serverless::Function",
      "Properties": {
        "CodeUri": ".",
        // SNS will trigger the function asynchronously
        "Events": {
          "SNS": {
            "Type": "SNS",
            "Properties": {
              "Topic": "my-sns-topic"
            }
          }
        },
        // Configure a failure destination for the function
        "EventInvokeConfig": {
          "DestinationConfig": {
            "OnFailure": {
              "Type": "SQS",
              "Destination": "arn:aws:sqs:us-east-1:111122223333:my-dlq"
            }
          }
        }
      }
    }
  }
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
SNSFunction:
  Type: AWS::Serverless::Function
  Properties:
    CodeUri: .
    # SNS will trigger the function asynchronously
    Events:
      SNS:
        Type: SNS
        Properties:
          Topic: my-sns-topic
    # Configure a failure destination for the function
    EventInvokeConfig:
      DestinationConfig:
        OnFailure:
          Type: SQS
          Destination: arn:aws:sqs:us-east-1:111122223333:my-dlq
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
functions:
  hello:
    handler: main.handler
    # SNS will trigger the function asynchronously
    events:
      - sns:
          topicName: my-sns-topic
    # Configure a failure destination for the function
    destinations:
      onFailure: arn:aws:sqs:us-east-1:111122223333:my-dlq
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
resource "aws_lambda_function" "this" {
  function_name = "my-function"
  runtime       = "python3.8"
  handler       = "main.handler"
  filename      = "function.zip"
}

resource "aws_lambda_permission" "this" {
  action        = "lambda:InvokeFunction"
  function_name = aws_lambda_function.this.function_name
  # Grants the permission to SNS to invoke this function
  # SNS will trigger the function asynchronously
  principal     = "sns.amazonaws.com"
}

resource "aws_lambda_function_event_invoke_config" "example" {
  function_name = aws_lambda_alias.example.function_name

  # Configure a failure destination for the function
  destination_config {
    on_failure {
      destination = "arn:aws:sqs:us-east-1:111122223333:my-dlq"
    }
  }
}

See also