0

I'm fairly new to both AWS lambda and node.js. I've wrestled through some of the asynchronous architecture such that I am familiar, but still inexperienced, with callbacks. I'm sure that this is related somehow, but I do not understand why, because it runs perfectly if I test it locally. I have set up the environment variable correctly and tested that it is being passed too.

In the code snippet below, I am using Claudia Bot Builder to grab a slack-slash-command message, passing it to this SlackResponse function, which is using the Node Hubspot API to make a query by username. For some reason, the client.contacts search command is never called. All console.log() reports show up, but the callback for the search never seems to execute, even asynchronously.

function SlackResponse(message, request, debug, currentresponse){
var SlackResponse = currentresponse;
var SenderID = message.originalRequest.user_name;
var CustomerID = 0;

if (debug){
    SlackResponse += 'Slack Debug On' + '\r';
    SlackResponse += 'SenderID: ' + SenderID + '\r';
}
client.useKey(process.env.HAPI_Key);
console.log('API Key set \r');
console.log(message);
console.log(currentresponse);

client.contacts.search(SenderID,
    function processSearchResult(err, res) {
        console.log('In processSearchResult function \r');
        console.log(JSON.stringify(res));
        if (err) { console.log('uh oh'); throw err; }
        if (res.total === 0)
        {
            if(debug){console.log('New Customer Identified' + '\r')}

            // Create a new Contact
            var payload = {
                "properties": [
                    {
                        "property": "firstname",
                        "value": SenderID
                    }]
            }
            client.contacts.create(payload, function(err, res){
                if (err) { throw err; }
                CustomerID = res.vid;
                if(debug){console.log('New Customer Created with CustomerID: ' + CustomerID + '\r')}
            })
        }
        else
        {
            CustomerID = res.contacts[0].vid;
            if(debug){console.log('Hubspot CustomerID:' + CustomerID + '\r')}
        }

      }
);
console.log('About to return \r');
return SlackResponse;

}

Can anyone explain why this is occurring? Is this a permissions issue? Why does this run locally but not in AWS?

Mark B
  • 183,023
  • 24
  • 297
  • 295
dave
  • 3
  • 2
  • What is logged in CloudWatch Logs when the function finishes executing? Is there an error message? Does the function timeout? What is the function's configured timeout value? Have you configured this function to run inside a VPC without a NAT gateway? – Mark B Jun 17 '17 at 16:58
  • CloudWatch displays logs up to the client.contacts.search() call, all as expected. No error message that I can see, although it is possible I am not looking in the right place as a rookie here. Function is using the default timeout value, which I believe is two minutes by default in Claudia. I'm not sure how to answer your last question because I don't know what that means. – dave Jun 17 '17 at 17:13
  • There should be a log line that says how much time the function executed, and if it exited normally or had an error or a timeout. – Mark B Jun 17 '17 at 17:30
  • The question about VPC is simple, when you created the Lambda function did you leave the VPC settings as default or did you select a VPC? – Mark B Jun 17 '17 at 17:31
  • Dug into advanced config, and no VPC is selected currently. Function is executing in less than 200ms. Here is the end of the console log: END RequestId: 64f2e5f0-5387-11e7-bd47-f15cb5f75744 REPORT RequestId: 64f2e5f0-5387-11e7-bd47-f15cb5f75744 Duration: 194.88 ms Billed Duration: 200 ms Memory Size: 128 MB Max Memory Used: 42 MB – dave Jun 17 '17 at 18:07
  • This may sounds silly, but are we sure `.contacts` is defined when its running out there? – Catalyst Jun 17 '17 at 19:27
  • You might be on to something, but I don't know how to check. It looks like my API usage is increasing, despite never seeing the console logs. But it also isn't executing like it should. Is it possible that because it's executing asynchronously that it loses scope on the parameters I'm passing? – dave Jun 17 '17 at 19:41
  • @dave that does not look like it could be happening. Does it log out `'In processSearchResult function \r'` and then stop? – Catalyst Jun 17 '17 at 19:47
  • I think the api call is happening, that somehow the handling of the response is being bungled. Say res is undefined despite there being no network error, for example. It may even be the underlying library. – Catalyst Jun 17 '17 at 19:49
  • @Catalyst, no, I never see the first log in processSearchResult callback. – dave Jun 17 '17 at 19:55

1 Answers1

2

This seems like a JavaScript promises issue.

Claudia API and Bot Builders are using JavaScript promises to handle async operations. If you run this example locally it will work because your function will execute, however if you run it on Lambda function client.contacts.search(SenderID, will break promise chain and Lambda function will be closed, which means that nothing else will be executed.

To solve that problem you need to wrap async operations to JavaScript promises if they don't support them out of the box. For example:

setTimeout(function () {
  return 'Hello'
}, 1000)

Should become:

return Promise(function(resolve, reject) {
  setTimeout(function () {
    resolve('Hello')
  }, 1000)
})

Or, in your example:

return new Promise(function(resolve, reject) {
  client.contacts.search(SenderID, function (err, res) {
    if (err) {
      return reject(err)
    }

    // Do your logic
    resolve(finalResult)
  }
}