skip to Main Content

So AWS announced Lambda Snapstart very recently, I tried to give it a go since my application has cold start time ~4s.

I was able to do this by adding the following under resources:

- extensions:
      NodeLambdaFunction:
        Properties:
          SnapStart:
            ApplyOn: PublishedVersions

Now, when I actually go to the said lambda, this is what I see :

enter image description here

So far so good!
But, the issue is that when I check my Cloudwatch Logs, there’s no trace of Restore Time instead the good old Init Duration for cold starts which means Snapstart isn’t working properly.

I dug deeper, so Snapstart only works for versioned ARNs. But the thing is Serverless already claims that :

By default, the framework creates function versions for every deploy.

And on checking the logs, I see that the logStreams have the prefix : 2022/11/30/[$LATEST].

When I check the Versions tab in console, I see version number 240. So I would expect that 240 is the latest version of this lambda function and this is the function version being invoked everytime.

However, clicking on the version number open a lambda function with 240 attached to its ARN and testing that function with Snapstart works perfectly fine.

So I am confused if the LATEST version and version number 240 ( in my case ), are these different?

  • If no, then why isn’t Snapstart automatically activated for LATEST?
  • If yes, how do I make sure they are same?

4

Answers


  1. SnapStart is only available for published versions of a Lambda function. It cannot be used with $LATEST.

    Using Versions is pretty hard for Serverless Framework, SAM, CDK, and basically any other IaC tool today, because by default they will all use $LATEST to integrate with API Gateway, SNS, SQS, DynamoDB, EventBridge, etc.

    You need to update the integration with API Gateway (or whatever service you’re using) to point to the Lambda Version you publish, after that Lambda deployment has completed. This isn’t easy to do using Serverless Framework (and other tools). You may be able to achieve this using this traffic-shifting plugin.

    Login or Signup to reply.
  2. In case you use stepFuntions to call your lambda function, you can set useExactVersion: true in

    stepFunctions:
      stateMachines:
        yourStateMachine:
          useExactVersion: true
          ...
          definition:
            ...

    This will reference the latest version of your function you just deployed

    Login or Signup to reply.
  3. This has got to be one of the worst feature launches that I have seen in a long time. How the AWS team could put in all the time and effort required to bring this feature to market, while simultaneously rendering it useless, because we can’t script the thing is beyond me.

    We were ready to jump on this and start migrating apps to lambda, but now we are back in limbo. Even knowing there was a fix coming down the line would be something. Hopefully somebody from the AWS lambda team can provide some insights…

    Here is a working POC of a serverless plugin that updates the lambda references to use the most recent version. This fixed the resulting cloud formation code and was tested with both SQS and API-Gateway.

    'use strict'
    
    class SetCycle {
      constructor (serverless, options) {
        this.hooks = {
          // this is where we declare the hook we want our code to run
          'before:package:finalize': function () { snapShotIt(serverless) }
        }
      }
    }
    
    function traverse(jsonObj,functionVersionMap) {
        if( jsonObj !== null && typeof jsonObj == "object" ) {
            Object.entries(jsonObj).forEach(([key, value]) => {
                if(key === 'Fn::GetAtt' && value.hasOwnProperty('length') && value.length === 2 && value[1] === "Arn" && functionVersionMap.get(value[0])){
                    console.log(jsonObj);
                    let newVersionedMethod = functionVersionMap.get(value[0]);
                    
                    delete jsonObj[key];
                    jsonObj.Ref = newVersionedMethod;
                    
                    console.log('--becomes');
                    console.log(jsonObj);
                }else{
                // key is either an array index or object key
                    traverse(value,functionVersionMap);
                }
            });
        }
        else {
            // jsonObj is a number or string
        }
    }
    
    function snapShotIt(serverless){
        resetLambdaReferencesToVersionedVariant (serverless)
    }
    
    function resetLambdaReferencesToVersionedVariant (serverless) {
      
      const functionVersionMap = new Map();
      
      let rsrc = serverless.service.provider.compiledCloudFormationTemplate.Resources
      // build a map of all the lambda methods and their associated versioned resource
      for (let key in rsrc) {
        if (rsrc[key].Type === 'AWS::Lambda::Version') {
          functionVersionMap.set(rsrc[key].Properties.FunctionName.Ref,key);
        }
      }
     
      
      // loop through all the resource and replace the non-verioned with the versioned lambda arn reference
      for (let key in rsrc) {
        if (! (rsrc[key].Type === 'AWS::Lambda::Version' || rsrc[key].Type === 'AWS::Lambda::Function')) {
          console.log("--" + key);
          traverse(rsrc[key],functionVersionMap);
        }
      }
      
      // add the snapshot syntax
      for (let key in rsrc) {
        if (rsrc[key].Type === 'AWS::Lambda::Function') {
          console.log(rsrc[key].Properties);
          rsrc[key].Properties.SnapStart = {"ApplyOn": "PublishedVersions"};
          console.log("--becomes");
          console.log(rsrc[key].Properties);
        }
      }
    
      // prints the method map
      //for(let [key,value] of functionVersionMap){
        //console.log(key + " : " + value);
      //}
    
    }
    
    // now we need to make our plugin object available to the framework to execute
    module.exports = SetCycle
    
    Login or Signup to reply.
  4. I was able to achieve this by updating my serverless version to 3.26.0 and adding the property snapStart: true to the functions that i have created. currently serverless creates version numbers and as soon as the new version is published the SnapStart gets enabled to latest version.

    ApiName:
      handler: org.springframework.cloud.function.adapter.aws.SpringBootApiGatewayRequestHandler
      events:
        - httpApi:
            path: /end/point
            method: post
      environment:
        FUNCTION_NAME: ApiName
      runtime: java11
      memorySize: 4096
      snapStart: true
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search