This will be a short, but hopefully useful post for anyone trying to keep Lambda functions warm when using them in AWS Step Functions. It was not as straightforward as I initially thought – simply adjusting the provisionedConcurrency
value in the function configurations will not suffice. In short, you must specify the Provisioned Concurrency alias in the step function configuration in order for it to be used by the state machine.
Let’s start with a minimal step function example:
YAML
service: step-function-test
frameworkVersion: '3'
provider:
name: aws
runtime: python3.10
timeout: 60
memorySize: 512
versionFunctions: false
stage: ${opt:stage, "sbx"}
region: us-east-1
functions:
hello:
handler: handler.hello
hi:
handler: handler.hi
stepFunctions:
stateMachines:
helloStepFunc:
name: 'hello'
definition:
Comment: "A Hello World example"
StartAt: HelloWorld
States:
HelloWorld:
Type: Task
Resource: !GetAtt hello.Arn
Next: HiWorld
HiWorld:
Type: Task
Resource: !GetAtt hi.Arn
End: true
plugins:
- serverless-step-functions
These Lambda functions are of course not configured with provisionedConcurrency
and may suffer from cold starts. If we simply enable it in the serverless.yml, deploy, and invoke the step function again, we won’t see an improvement. Reviewing the logs, we can identify the invoked version:
The step function is currently configured to invoke the $LATEST
version of the Lambda. The docs on Configuring provisioned concurrency describe the problem:
Provisioned Concurrency is not supported on the unpublished version of the function ($LATEST). Ensure your client application is not pointing to $LATEST before configuring provisioned concurrency.
In this case, the client application is the state machine configuration. Using serverless framework’s built-in support for provisionedConcurrency
, we can enable it and infer the aliases. Serverless generates the provisioned concurrency alias like this:
JavaScript
getLambdaProvisionedConcurrencyAliasLogicalId(functionName) {
return `${this.getNormalizedFunctionName(functionName)}ProvConcLambdaAlias`;
}
Here’s the updated serverless.yml:
YAML
service: step-function-test
frameworkVersion: '3'
provider:
name: aws
runtime: python3.10
timeout: 60
memorySize: 512
versionFunctions: false
stage: ${opt:stage, "sbx"}
region: us-east-1
functions:
hello:
handler: handler.hello
provisionedConcurrency: 3
hi:
handler: handler.hi
provisionedConcurrency: 3
stepFunctions:
stateMachines:
helloStepFunc:
name: 'hello'
definition:
Comment: "A Hello World example"
StartAt: HelloWorld
States:
HelloWorld:
Type: Task
Resource: !Ref HelloProvConcLambdaAlias
Next: HiWorld
HiWorld:
Type: Task
Resource: !Ref HiProvConcLambdaAlias
End: true
plugins:
- serverless-step-functions
Note the AWS::Lambda::Alias
resource returns the ARN directly when used with Ref
.
Now we can invoke the step function with sls invoke stepf -n helloStepFunc
and see the version updated in the CloudWatch logs:
Share this: