3

In my local mocha tests the following handler function works just fine. However, when I upload to AWS (using Serverless framework) it times out (unless you don't provide a uid parameter where it then correctly responds immediately).

What's particularly odd is that in less than 3 seconds (timeout is set at 5 seconds), the job completes and even the "post-facto" log message is output but it somehow calling the callback and that is not completing the Lambda function

Here's the cloudwatch log:

![enter image description here]1

And here's the handler function:

export const handler = (event: IRequestInput, context: IContext, cb: IGatewayCallback) => {
  console.log('EVENT:\n', JSON.stringify(event, null, 2));
  const uid = _.get(event, 'queryStringParameters.uid', undefined);
  if(!uid) {
    cb(null, {
      statusCode: 412,
      body: 'no User ID was provided by frontend'
    });
    return;
  }

  oauth.getRequestToken()
    .then(token => {
      console.log('Token is:\n', JSON.stringify(token, null, 2));
      console.log('User ID: ', uid);
      token.uid = uid;
      return Promise.resolve(token);
    })
    .then((token) => {
      console.log('URL: ', token.url);
      cb(null, {
        statusCode: 200,
        body: token.url
      });
      console.log('post-facto');
    })
    .catch((err: PromiseError) => {
      console.log('Problem in getting promise token: ', err);
      cb(err.message);
    });

};
ken
  • 8,763
  • 11
  • 72
  • 133

2 Answers2

10

Add the following as the first line of your handler function:

context.callbackWaitsForEmptyEventLoop = false
idbehold
  • 16,833
  • 5
  • 47
  • 74
  • wow. that worked. need to grab a coffee immediately but no idea "why" it worked yet. I'll look into it but if you're free could you explain what lead you to this? – ken Nov 24 '16 at 07:31
  • @ken essentially Node will wait for an empty event loop before exiting its process. So if you have a js file that simply does a `(function recurse () { setInterval(recurse, 1) })()` then run that with node the process will never exit until you kill it manually. The callback Lambda provides will respect this unless you add the line from my answer. In which case Lambda will essentially just call `process.exit()` after you invoke the callback. – idbehold Nov 24 '16 at 19:02
  • 3
    @ken it also means that something in your code is causing the event loop to never drain. DB connections are a typical cause of this as they will open up a socket and node won't consider the event loop empty while a socket is still open. – idbehold Nov 24 '16 at 19:08
  • Ahhh. A DB connection makes a lot of sense. Thanks. – ken Nov 24 '16 at 19:45
  • you are awesome @idbehold – prashant Jan 20 '17 at 09:30
0

I guess that you're using lambda with "Node.js Runtime 0.10"

So you should add

context.done(null, 'Terminate Lambda');

to terminate the execution.

As the AWS lambda document, it mentions that:

The callback is supported only in the Node.js runtime v4.3. If you are using the earlier runtime v0.10.42, you need to use the context methods (done, succeed, and fail) to properly terminate the Lambda function.

Please refer this link for above information

Ngoan Tran
  • 1,507
  • 1
  • 13
  • 17