dougmoscrop / serverless-http

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

Express - lambda exits before handler resolves #241

Closed ShantanuNair closed 3 months ago

ShantanuNair commented 1 year ago

I have a lambda that is being used to receive webhook events. Some of the tasks it has to do are a tad longer running, and the source of the webhook event retries if not received a 20X response. I do not intend to respond with HTTP error codes to the webhook dispatcher, and wish to immediately respond with a 20X. So to test things out, I moved res.send(202) to before the route returns. Instead of waiting for the route's returned promise to resolve, the lambda ends soon after res.send() is called.

What I expected (and what I observed with serverless-offline simulating the lambda):

What I observed when deployed:

The webhook handler looks like this

webhookRouter.post('/webhook', async (req, res) => {
  try {
      console.log("Received webhook event");
      return res.status(202).send('Event received and being processed');
      await doSomeOtherStuffThatWouldCauseARetry()
      console.log("This runs on serverless-offline, but is never executed when deployed on lambda")
    } catch {
      res.status(202).send('Event received and being processed');
    }
}

I'm unsure if this is expected, due to the lambda environment, or maybe this has something to do with the waiting for empty event loop setting, although I don't see why that would be required to await on the route handler's returned promise.

dougmoscrop commented 1 year ago

I'm not sure, but this might be a bug in serverless-offline and how it emulates promise-based responses. This reason for this is that your promise in your handler (the async (req, res) => {}) part is technically detatched from the promise this library creates in the handler function.

steffenstolze commented 1 year ago

Isn't that expected JavaScript behaviour since you explicitly write return before res.status(202).... ? return exits the function and await doSomeOtherStuffThatWouldCauseARetry() is not reachable.

Without testing this, if you just leave out return, the rest of the code would run. But you could not send any other data to the requester, since you already sent the response..

Isn't it actually impossible for Lambda to continue the execution after the response has been sent?

dougmoscrop commented 1 year ago

Ah I missed the return before that await - yes that code is essentially broken.

As for continuing after execution, it's possible with some runtime + extension magic but it requires a bit of coordination

ShantanuNair commented 1 year ago

@steffenstolze @dougmoscrop My bad, iirc the code in question was not supposed to have the return statement there. What I was trying to achieve was indeed, sending the response, and then continuing with the following code - essential and early reply, and then waiting for the rest of the event loop to finish. I remember it worked as I'd expected in serverless-offline, but not when deployed.