dougmoscrop / serverless-http

Use your existing middleware framework (e.g. Express, Koa) in AWS Lambda 🎉
Other
1.73k stars 167 forks source link

Async data loading before bootstrapping #254

Closed saifkhan192 closed 5 months ago

saifkhan192 commented 1 year ago

Hi guys!, I hope you are going great!

I want to load asynchronous configs from remote server before bootstrapping or initializing the app.

What I come up with is the below code for the lambda.js file. But the problem here is that it will do the bootstrapping or loading remote configs on first request whitch I dont want. Instead I want to resolve the async config loading and then initializing the proxy function

` const loadApp = async () => { await require('./config')(); const app = require('./app'); return serverless(app, {}); };

let handle = null; module.exports.handler = async (event, context) => { if (handle === null) { handle = await loadApp(); } return handle(event, context); }; `

Source code image is here:

Screenshot 2022-10-28 at 10 54 53 PM
dougmoscrop commented 1 year ago

So there's a couple things to think about here: one is that Lambda does not spin up a function unless there is a request, so in a sense, this initialization is always happening at first request. You can't get around cold starts.

However, waiting until the Lambda "state machine" is processing a request is suboptimal because ideally you want to be parsing and loading your app code during the init phase, which gives you 2 full vCPUs worth of performance, not the request phase, which is going to be proprtional to whatever your RAM is set to.

So the "cheap" way of doing this is just move the loadApp() call outside of the handler and await it inside the handler

const loading = loadApp().then(hanlde => { return { handle }).catch(err => { return { err } })

module.exports.handler = async (event, context) => {
  const { handle, err } = await loading
  if (err) {
    throw err
  }
  return handle(event, context)
})

This isn't optimal because it technically doesn't hold up the init phase and so it starts init the jumps in to request which casues a drop in allocated CPU performance, meaning it makes your cold start longer due to reduced vCPU capacity.

The ideal solution is to move to ESM and use top-level await.

import App from './app'
import loadConfig from './config'

const config = await loadConfig()
const app = new App(config)