aws / aws-lambda-nodejs-runtime-interface-client

Apache License 2.0
180 stars 56 forks source link

Inconsistency between RIC in container and Node in zip deployment #17

Open jeffmcaffer opened 3 years ago

jeffmcaffer commented 3 years ago

I created two functions, one deployed as a custom container using this runtime interface and the other as a Node handler deployed as a zip. The event argument to the two handlers is different. Both functions are triggered by a REST API gateway POST route configured in the same way AFAICT.

Container + RIC

This setup seems to get the body of the event as an object (already parsed) and is is expected to return the result object as the response. The handler does not have access to the request headers etc. Nor can the handler control the response status code etc. Here is a rough outline of the handler.

module.exports.handler = async (event) => {
  // notice here `event` is already the body as an object and can be destructured
  const { params, contextParts } = event
  const result = { some: 'thing', that: 'was', computed: true }
  // notice the `result` is just the object computed
  return result
}

Node and zip deploy

In this case the handler is given the full REST API event object headers, body, ... and it must parse the body. Note also that the return value appears to need to be a structured object that has the statusCode and a stringified version of the return value.

module.exports.handler = async (event) => {
  // notice here `event` is the full event with headers... and the body is not parse
  const { body, headers } = event
  const { params, contextParts } = JSON.parse(body)
  const result = { some: 'thing', that: 'was', computed: true }
  // notice the `result` has to be a structure with status and headers, and the body must be stringified
  return {
    statusCode: 200,
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify(result, null , 2)
  }
}

Questions

  1. Have I done something wrong in one of these? Looking at the code for this client it very clearly parses the body and leaves off the headers when calling the handler. The examples for the other scenario are pretty clear about getting the full event and indeed AFAICT the implementer doesn't have any control over the shape of the passed in event.
  2. How will this work with other events (from other than the REST API gateway)? Do they all have a body and headers? Seems like this client may be assuming quite a bit about the calling context.
hugomarcelino-spotqa commented 3 years ago

I'm seeing this happening and I'm also confused if I'm missing something. I'm having different behaviors between running in the container and running in AWS.

paya-cz commented 3 years ago

I noticed different inconsistency. If zip-based lambda throws an error, lambda will terminate the lambda container and next invocation will always run in a cold-started new container. Docker lambda instead reuses lambda containers even when the invocation throws an error.

GetafixIT commented 2 years ago

I am surprised to find these questions (and others) have gone unanswered here. @jeffmcaffer thanks for your issue as it could explain why my function isn't working in AWS.

I've been trying to work out why my container image runs the function in docker-compose locally, but not in AWS. Could make sense if the headers aren't there & gives me a new angle to debug at least. Quite possibly my knowledge of API gateway or triggers is the issue though :) Not finding the answers online though.

It would be useful to create function from a NodeJS container. I'd like to see a NodeJs application run from a platform agnostic container, deployed into a function. Perhaps a process.exit(0) would terminate the route handler on completion or perhaps structure the application as a middleware module that could be used by the lambda implementation.

In my tests I can see a significantly better warmup time when using containers & would like to prove that using a NodeJS runtime.

GetafixIT commented 2 years ago

I've been able to get my container image running in AWS now...

The function itself receives whatever its passed in the event invocation.

So if you create a container and run it locally, then curl with

curl -XPOST "http://localhost:8080/2015-03-31/functions/function/invocations" -d '{"headers": {"someHeader": 12345677654321}}'

The function will receive the headers passed though from the RIC implementation.

The contents of the -d flag above you can pass that payload as event json under the test tab

{
  "headers": {
    "someHeader": 12345677654321
  }
}

So then headers show up in the container... but I've not worked out yet how to get the request headers to pass through.

GetafixIT commented 2 years ago

I got the headers through, but they needed to be passed in from a rest API gateway with a mapping template.

What I do see as inconsistent is that the lambda function published with SAM needs to return and object with statusCode, headers and a body. Whereas from a docker container needs only to return the body.