Dev notes: aws-cdk not updating Lambda function
So you created a Lambda function via aws-cdk. The first deploy worked fine and you were able to try the function. When attempting to deploy an update of the function, no changes are deployed. The output of the cdk diff
command says “There were no differences”.
When using the aws-cdk Lambda docs and examples, the code for the Lambda function is fetched by lambda.Code.fromAsset()
This is from a local directory within the cdk project and works as expected because the cdk is able to calculate a hash of the files to detect a change in the code.
My GitHub Actions workflow was pushing zip files to S3 containing the code for the Lambda functions. This meant that I use lambda.Code.fromBucket
.
Something like this:
// bucket is of type Bucket construct from aws-cdk/aws-s3 package.
// This is path of the release zip file in s3.
const releaseFileKey = "my-function/latest.zip"
const fn = new lambda.Function(this, 'MyFunction', {
runtime: lambda.Runtime.NODEJS_14_X,
handler: 'handler.hello',
code: lambda.Code.fromBucket(bucket, releaseFileKey)
})
cdk would not detect updates to the lambda function. There are some notes in the cdk documentation that mentions passing the version options to inform cdk that an update is being made.
I was looking for a mechanism to be able to pass the version of the lambda function to deploy, to the cdk deploy
command. I definitely do not want to be updating the s3 release file name in the stack definitions manually everytime I want to deploy.
I stumbled upon CfnParameters
. This can be used to pass parameters to the cdk on the command line.
I made some code changes to read releaseFileKey
using CfnParameter
. Here is how I would pass the release file key in the command line.
$ cdk deploy MyAppStack \
--parameter MyAppStack:releaseFileKey=my-function/3badf1b7.zip
Nope - that did not work. The Lambda function still wasn’t being updated when I passed a new file key that included the git commit SHA in the file name. When I opened the CloudFormation templates in cdk.out
dir, I noticed that the places where I was expected to see the release file key, there was something like {"ref": "releaseFileKey"}
.
I learnt that these CfnParameters are CloudFormation parameters that are injected during deploy time. The CloudFormation templates generated by cdk would always have placeholders for these parameters and therefore the cdk would not detect any changes to deploy.
Solutions that worked
Option-1: Read the S3 file key from environment variables
const fn = new lambda.Function(this, 'MyFunction', {
runtime: lambda.Runtime.NODEJS_14_X,
handler: 'handler.hello',
code: lambda.Code.fromBucket(bucket, process.env.RELEASE_FILE)
})
Run the diff command now and you’ll notice cdk is detecting changes to the stack and will update the Lambda function.
RELEASE_FILE="my-function/3badf1b7.zip" cdk diff --all
Option-2: Add the code version as an env var that is passed to the Lambda function
Incase your S3 file name always remains the same, then the other option is to pass some environment variable to your Lambda function that always changes when your code changes.
The easy way is to pass the git commit SHA like below.
const fn = new lambda.Function(this, 'MyFunction', {
runtime: lambda.Runtime.NODEJS_14_X,
handler: 'handler.hello',
code: lambda.Code.fromBucket(bucket, "my-function/latest.zip")
environment: {
GIT_VERSION: process.env.RELEASE_VERSION
}
})
And then pass the env var to the diff or deploy commands like this.
RELEASE_VERSION="3badf1b7" cdk diff --all
Option-3: Pass version options to lambda.Function
You can also pass the version options to lambda.Function
like below. But it is required that you access the currentVersion
property after the lambda function is declared. This ensures that the version is output to the CloudFormation template. Notice the last line in the snippet below.
If you notice below, the snippet still reads the release version from an env var.
const fn = new lambda.Function(this, 'MyFunction', {
runtime: lambda.Runtime.NODEJS_14_X,
handler: 'handler.hello',
code: lambda.Code.fromBucket(bucket, "my-function/latest.zip")
currentVersionOptions: {
codeSha256: process.env.RELEASE_VERSION
}
})
fn.currentVersion
Try running the cdk diff or deploy commands with RELEASE_VERSION
env var.
RELEASE_VERSION="3badf1b7" cdk diff --all