Does it matter, from cold-start perspective, whether we write handler in the same file or in multiple files for AWS Lambda?

Viewed 109

I am writing my lambda handlers using serverless.com framework. Does the 2nd way (multiple file handler functions) cause more cold start than the first one?

For example, at 11:00:00am my app calls GET /pets, and at 11:00:30am my app calls POST /store. If both functions are packaged into the same lambda package, then 2nd call won't cause cold start; however, if they are packaged into different lambda package, then 2nd call will be a cold start.

Thanks for sharing

One way to write it is the following

--- single file handlers way ----

...
functions:
  listPets:
    handler: handler.handler1
    events:
      - http:
          method: get
          path: pets
  addStore:
    handler: handler.handler2
    events:
      - http:
          method: post
          path: stores
...

// handler.js

// handle GET /pets
exports.handler1 = async (event) { ... }

// handle POST /stores
exports.handler2 = async (event) { ... }

...

And the other way to organize it is the following:

--- multiple file handlers way ----

...
functions:
  listPets:
    handler: handler1.handler1
    events:
      - http:
          method: get
          path: pets
  addStore:
    handler: handler2.handler2
    events:
      - http:
          method: post
          path: stores
...

// handler1.js

// handle GET /pets
exports.handler1 = async (event) { ... }


// handler2.js
// handle POST /stores
exports.handler2 = async (event) { ... }

...
2 Answers

Both of your two approaches will cause two lambda functions (i.e. listPets and addStore) to be created, since one lambda function cannot have two handlers configured in the function setting. However, you could put both of the GET and POST logic inside one handler. For example,

exports.handler =  async function(event, context) {
  switch (event.httpMethod) {
    case 'GET':
      // ...
      break;
    case 'POST':
      // ...
      break;
    default:
      // ...
  }
}

Then let the API Gateway call the the same lambda function on GET and POST requests:

functions:
  sharedFunction:
    handler: example.handler
    events:
      - http:
          method: get
          path: pets
      - http:
          method: post
          path: stores

This will slightly reduce the chance of code start, but it will result in more complex code structure in the shared lambda function. IMO you should always split the code that has separate logics into separate lambda functions if possible to reduce potential bugs.

A separately defined Lambda function with a different event to trigger it, even cases where the same handler handles multiple events, will invoke seperate instances which means they all suffer some form of cold start. However, you may want to first determine whether a cold start is an actual problem. Looking at a project I have access to that received over 3 000 000 Lambda invocations every 24 hour's, only something like 0.02 percent of those invocations were actually cold starts. So spending an inordinate amount of time reducing cold starts may or may not be actually useful to your optimisation process.

The easiest and most effective two methods to reduce cold starts is:

  1. Pay a bit more by increasing the memory size setting. Memory size also linearly increases CPU allocation (going from 128 MB to 256 MB effectively doubles CPU allocation) and it has been shown to also decrease cold start time. This will also make your Lambda execute faster so its a pretty good bonus.
  2. Pay a lot more and use provisioned concurrency which is a way to tell AWS to always have a warm Lambda sitting around waiting for requests so you never have a cold start.
Related