aws / aws-cdk

The AWS Cloud Development Kit is a framework for defining cloud infrastructure in code
https://aws.amazon.com/cdk
Apache License 2.0
11.5k stars 3.85k forks source link

(aws_stepfunctions_tasks): Lambda Functions deployed with LambdaInvoke won't generate Cloudwatch metrics #24048

Open quentinbarbault opened 1 year ago

quentinbarbault commented 1 year ago

Describe the bug

Hello,

I think I've found an issue with CDK and the way it adds Lambda function to the JSON definition with LambdaInvoke. This disables the possibility to get [Lambda Function Metrics] in Cloudwatch.

Let me explain.

We are using CDK to create our State Machine. To add Lambda Functions to our State Machine, we use LambdaInvoke, as intended. https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_stepfunctions_tasks.LambdaInvoke.html

This generates a definition, with States juste like this :

"LambdaState1": {
    "Next": "LambdaState2",
    "Type": "Task",
    "Resource": "arn:aws:states:::lambda:invoke",
    "Parameters": {
        "FunctionName": "arn:aws:lambda:eu-west-3:ACCOUNT:function:Lambda1ARN"
    }
},

Please note that this definition has :

Our state machine is running fine but this definition doesn't generate any metrics (such as "LambdaFunctionsStarted", "LambdaFunctionsSucceeded" and so on) for our deployed lambda functions.

As a matter of fact, the State Machine does not consider this state (here LambdaState1) as a LambdaFunction, but as a simple Task. Which, I presume, is the issue here.

When playing with this, I've found that this following definition does work.

"LambdaState1": {
    "Next": "LambdaState2",
    "Type": "Task",
    "Resource": "arn:aws:lambda:eu-west-3:ACCOUNT:function:Lambda1ARN"
},

The state is considered a LambdaFunction, not a Task, from the state machine's point of view. And, more importantly, metrics from this Lambda are indeed created.

But I can't seem to figure out how to force LambdaInvoke to generate something like this. With the ARN as a ressource.

So I suspect something is not quite right here.

Expected Behavior

I would expect LambdaInvoke to add lambda functions as LambdaFunction, and not as Task.

Even if the documentation clealy states : "Invoke a Lambda function as a Task.". If so, how can I force CDK to treat my Lambda as a LambdaFunction ? Is there any property available to do that ?

Current Behavior

Adding a lambda function to a state machine like this:

const myLambdaState = new LambdaInvoke(
            this,
            "my-lambda-state",
            {
                lambdaFunction: new NodeJsFunction(...),
                retryOnServiceExceptions: false,
            }
        );

Generates the following definition :

"myLambdaState": {
    "End": "true",
    "Type": "Task",
    "Resource": "arn:aws:states:::lambda:invoke",
    "Parameters": {
        "FunctionName": "arn:aws:lambda:eu-west-3:ACCOUNT:function:Lambda1ARN"
    }
},

Instead of:

"myLambdaState": {
    "End": "true",
    "Type": "Task",
    "Resource": "arn:aws:lambda:eu-west-3:ACCOUNT:function:Lambda1ARN"
},

So the lambda is not considered a LambdaFunction, but a Task, for the StateMachine, hence not generating any Lambda specific metrics.

Reproduction Steps

Any lambda function deployed with LambdaInvoke will have the following definition:

"myLambdaState": {
    "End": "true",
    "Type": "Task",
    "Resource": "arn:aws:states:::lambda:invoke",
    "Parameters": {
        "FunctionName": "arn:aws:lambda:eu-west-3:ACCOUNT:function:Lambda1ARN"
    }
},

Any new execution will work but you'll find that no metrics in [Lambda Function Metrics] is available.

Possible Solution

When using LambdaInvoke, CDK could create the following definition instead:

"myLambdaState": {
    "End": "true",
    "Type": "Task",
    "Resource": "arn:aws:lambda:eu-west-3:ACCOUNT:function:Lambda1ARN"
},

Additional Information/Context

No response

CDK CLI Version

2.63.1

Framework Version

No response

Node.js Version

16

OS

Windows

Language

Typescript

Language Version

No response

Other information

No response

pahud commented 1 year ago

You are right. LambdaInvoke is actually a task that extends sfn.TaskStateBase and execute the lambda:Invoke API call.

And according to the doc, we can pass the lambda func arn in the Resource attribute:

Alternatively, you can invoke a Lambda function by specifying a function ARN directly in the "Resource" field. When you invoke a Lambda function in this way, you can't specify .waitForTaskToken, and the task result contains only the function output.

{  
   "StartAt":"CallFunction",
   "States":{  
      "CallFunction": {  
         "Type":"Task",
         "Resource":"arn:aws:lambda:us-east-1:123456789012:function:HelloFunction",
         "End": true
      }
   }
}     

It seems this alternative has some limitations though.

I am making this a p2 feature request. Any inputs on this are more than welcome here.