Problems in nodejs callback in custom alexa skill - node.js

I am trying to create a custom Alexa skill in which I am calling an API. But somehow my code is behaving weird.
CASE - 1
'firstChance': function () {
// Some code here//
getJSON(options, function (err, result) {
if (err) {
return console.log('ERROR while trying to get country names', err);
}
console.log(result);
});
this.emit(':tell', speechOutput, speechOutput);
},
In this case no errors are shown in cloudwatch but the control is not going to getJSON function eventhough this.emit() function is executed.
Below are the cloudwatch logs:
CloudWatch logs:

13:42:49
START RequestId: ************ Version: $LATEST

13:42:49
2018-04-03T13:42:49.578Z *************** Warning: Application ID is not set

13:42:49
END RequestId: *********************

13:42:49
REPORT RequestId: ************** Duration: 74.03 ms Billed Duration: 100 ms Memory Size: 128 MB Max Memory Used: 48 MB

13:42:51
START RequestId: ***************** Version: $LATEST

13:42:51
2018-04-03T13:42:51.647Z *********************** Warning: Application ID is not set

13:42:51
END RequestId: *************************

13:42:51
REPORT RequestId: ************************ Duration: 153.09 ms Billed Duration: 200 ms Memory Size: 128 MB Max Memory Used: 49 MB
CASE 2 :
'firstChance': function () {
// Some code here//
getJSON(options, function (err, result) {
if (err) {
return console.log('ERROR while trying to get country names', err);
}
console.log(result);
});
//this.emit(':tell', speechOutput, speechOutput);
},
In this case even though there are no errors in the logs and the control is going to getJSON, but alexa says "There was a problem with the requested skill's response".
Below are the cloudwatch logs:

13:35:32
START RequestId: ************************** Version: $LATEST

13:35:32
2018-04-03T13:35:32.896Z e16ddc70-3743-11e8-bf3b-a98fb0c89baf Warning: Application ID is not set

13:35:32
END RequestId: **************************

13:35:32
REPORT RequestId: ************************** Duration: 110.81 ms Billed Duration: 200 ms Memory Size: 128 MB Max Memory Used: 48 MB

13:35:35
START RequestId: ************************** Version: $LATEST

13:35:35
2018-04-03T13:35:35.549Z ************************** Warning: Application ID is not set

13:35:35
2018-04-03T13:35:35.861Z ************************** Response from Server started

13:35:35
2018-04-03T13:35:35.861Z ************************** Server Status: 200

13:35:35
2018-04-03T13:35:35.861Z ************************** Response Headers : {"server":"Cowboy","connection":"close","x-powered-by":"Express","content-type":"application/json; charset=utf-8","content-length":"187238","etag":"W/\"Vhlms2jCBxpTPF7sp9mxAw==\"","vary":"Accept-Encoding","date":"Tue, 03 Apr 2018 13:35:35 GMT","via":"1.1 vegur"}

13:35:35
2018-04-03T13:35:35.978Z ************************** Preparing the hash map...

13:35:36
2018-04-03T13:35:35.978Z ************************** [ { name: { common: 'Afghanistan', official: 'Islamic Republic of Afghanistan', native: [Object] }, tld: [ '.af' ], cca2: 'AF', ccn3: '004', cca3: 'AFG', currency: [ 'AFN' ], callingCode: [ '93' ], capital: 'Kabul', altSpellings: [ 'AF', 'Afġānistān' ], relevance: '0', region:

13:35:36
END RequestId: **************************

13:35:36
REPORT RequestId: ************************** Duration: 1249.65 ms Billed Duration: 1300 ms Memory Size: 128 MB Max Memory Used: 57 MB

13:35:36
START RequestId: ************************** Version: $LATEST

13:35:36
2018-04-03T13:35:36.954Z e46c4ff4-3743-11e8-a19e-036de9469172 Warning: Application ID is not set

13:35:36
END RequestId: **************************

13:35:36
REPORT RequestId: ************************** Duration: 1.97 ms Billed Duration: 100 ms Memory Size: 128 MB Max Memory Used: 57 MB
I am not able to resolve this.
I think, I have made some mistake in the callback of getJSON().

It looks like getJSON is an asynchronous function: meaning it returns immediately and it calls you back when the results are ready, or when an error is thrown.
So, in your example, getJSON is invoked, but it returns immediately, followed by your call to this.emit(':tell') which ends your handler and sends the respobse back to Alexa before getJSON has a chance to complete and call your anonymous function callback.
To solve, move this.emit(...) inside the callback function you are passing into getJSON
getJSON(options, function (err, result) {
if (err) {
// handle the error
this.emit(':tell', 'Error getting country names');
return console.log('ERROR while trying to get country names', err);
}
console.log(result);
// handle the successful result
this.emit(':tell', 'The country name was retrieved!');
});

Either try this,
'firstChance': function () {
// Some code here//
getJSON(options, function (err, result) {
if (err) {
return console.log('ERROR while trying to get country names', err);
}
console.log(result);
this.emit(':tell', speechOutput, speechOutput);
});
},
Or you can use set timeout :
'firstChance': function () {
// Some code here//
getJSON(options, function (err, result) {
if (err) {
return console.log('ERROR while trying to get country names', err);
}
console.log(result);
});
setTimeout(() => {
this.emit(':tell', speechOutput, speechOutput);
}, 2500)
},
Or you can try Async - Await which are now natively available in AWS Lambda as mentioned here https://aws.amazon.com/blogs/compute/node-js-8-10-runtime-now-available-in-aws-lambda/

Related

Random Instant Serverless Function Timeouts

We've been dealing with this issue in our t3 application for over a week now. Here is the error we are getting in the Vercel function logs: 
START RequestId: 3e875969-afce-4409-a7ae-96efc99ff603 Version: $LATEST 2023-01-31T13:43:45.065Z d22a6e7d-0ef6-4aa2-828e-ab70ceb99f02 ERROR Unhandled Promise Rejection  {\"errorType\":\"Runtime.UnhandledPromiseRejection\",\"errorMessage\":\"Error: timeout of 3000ms exceeded\",\"trace\":[\"Runtime.UnhandledPromiseRejection: Error: timeout of 3000ms exceeded\",\" at process.<anonymous> (file:///var/runtime/index.mjs:1194:17)\",\" at process.emit (node:events:525:35)\",\" at process.emit (node:domain:489:12)\",\" at emit (node:internal/process/promises:149:20)\",\" at processPromiseRejections (node:internal/process/promises:283:27)\",\" at process.processTicksAndRejections (node:internal/process/task_queues:96:32)\"]} [ERROR] [1675172625066] LAMBDA_RUNTIME Failed to post handler success response. Http response code: 400. RequestId: 3e875969-afce-4409-a7ae-96efc99ff603 Error: Runtime exited without providing a reason Runtime.ExitError END RequestId: 3e875969-afce-4409-a7ae-96efc99ff603 REPORT RequestId: 3e875969-afce-4409-a7ae-96efc99ff603. Duration: 12.50 ms Billed Duration: 13 ms Memory Size: 1024 MB Max Memory Used: 143 MB"
This only happens to Vercel deployed branches.Notice how it says that it is a 3000ms timeout error but the duration is only 12.50ms.
More details:
All necessary variables (like required user id's for API calls) are provided
The failing API calls succeed most of the time but about 1/5 times they fail.
Includes all our API calls
Example failing API call:
import type { NextApiRequest, NextApiResponse } from "next";
import { prisma } from "../../../server/db/client";
export default async function handler(  
req: NextApiRequest,  res: NextApiResponse) {  
if (req.method === "POST") {    
try {      
const data = JSON.parse(req.body);      
const update = await prisma.user.update({
        where: { id: data.id },
        data: data.data,      
});      
res.json(update);    
} catch (e: any) {      
res.status(500).json({ message: e.message });      
throw new Error("Could't update user:"+ e.message)
    }  
}
}
Note:
The error messages in the catch block are printed nowhere.This is more or less how we call all our serverless functions:
async function updateUserCurrentInstitution({ userId, institutionId }) {  
const response = await fetch(api.updateUser, {
    method: "POST",
    body: JSON.stringify({
      id: userId,
      data: {
        currentInstitution: institutionId,
      },
    }),
  });
  if (!response.ok) {
    throw new Error(response.statusText);
  }
  return response;
}
Any help would be greatly appreciated !

Schedule an Axios POST request

I got a client that's periodically sending GET requests to get a status of a demand that would've been generated earlier.
If the demand is ready, the server would respond with the information the client requested and should schedule an Axios POST request X minutes later.
Now, I've tried using Promises and setTimeout but they don't seem to work. I'm wondering whether the res.json I'm using is causing some issues.
api.get('/api-gitlab-launcher/request-status', async (gitlabRequest, res, next) => {
requestNb = gitlabRequest.headers['request-nb']
let obj = getRequestInfo(gitlabRequest, requestNb)
if (obj.requestStatus === "Not found") {
res.status(404)
res.send("RequestNb doesn't exist!")
} else if (obj.requestStatus === "Running") {
res.status(400)
res.send("Not finished yet")
} else if (obj.requestStatus === "finished") {
// This code will be scheduled to run after EXPIRATION_TIME
setTimeout(async () => {
let data = new FormData();
data.append("token", DESTROY_TOKEN);
data.append("ref", "terraform-v1");
data.append("variables[LAST_PIPELINE_ID]", pipelineId);
config = {
method: "POST",
url: `https://gitlab.com/api/v4/projects/${PROJECT_ID_DESTROY}/trigger/pipeline`,
data: data,
headers: {
...data.getHeaders(),
},
};
console.log('About to launch POST request')
await axios(config).then(
() => {
console.log("Resources destroyed.");
},
(error) => {
console.log(`error : ${error}`);
}
);
}, EXPIRATION_TIME);
res.status(200);
res.json({ec2Link: obj.ec2InstanceLink});
}
}
)
Am I doing it right? Did something wrong? I'm open to all criticism.
EDIT : The Axios POST request works without the setTimeout() wrap :
START RequestId: 03ee88f5-4abc-4f63-a59c-faa877c4b9f4 Version: $LATEST
END RequestId: 03ee88f5-4abc-4f63-a59c-faa877c4b9f4
REPORT RequestId: 03ee88f5-4abc-4f63-a59c-faa877c4b9f4 Duration: 1396.87 ms Billed Duration: 1400 ms Memory Size: 128 MB Max Memory Used: 91 MB Init Duration: 585.65 ms
START RequestId: 9ffcbec2-6445-422c-87b7-4a5164b0593b Version: $LATEST
END RequestId: 9ffcbec2-6445-422c-87b7-4a5164b0593b
REPORT RequestId: 9ffcbec2-6445-422c-87b7-4a5164b0593b Duration: 5.03 ms Billed Duration: 100 ms Memory Size: 128 MB Max Memory Used: 91 MB
START RequestId: 3577932d-53ec-4ee0-bf4a-f8aee12eba67 Version: $LATEST
END RequestId: 3577932d-53ec-4ee0-bf4a-f8aee12eba67
REPORT RequestId: 3577932d-53ec-4ee0-bf4a-f8aee12eba67 Duration: 1.60 ms Billed Duration: 100 ms Memory Size: 128 MB Max Memory Used: 91 MB
START RequestId: ab854edb-5a86-41b1-81de-8bec85a54ad2 Version: $LATEST
END RequestId: ab854edb-5a86-41b1-81de-8bec85a54ad2
REPORT RequestId: ab854edb-5a86-41b1-81de-8bec85a54ad2 Duration: 210.82 ms Billed Duration: 300 ms Memory Size: 128 MB Max Memory Used: 92 MB
START RequestId: 5f6ae638-ea84-4308-8ea5-6ae3d3fb0116 Version: $LATEST
END RequestId: 5f6ae638-ea84-4308-8ea5-6ae3d3fb0116
REPORT RequestId: 5f6ae638-ea84-4308-8ea5-6ae3d3fb0116 Duration: 516.74 ms Billed Duration: 600 ms Memory Size: 128 MB Max Memory Used: 93 MB
START RequestId: ddeb01ae-c9f6-40b2-ace5-b8b47ed21ebe Version: $LATEST
2020-09-09T20:15:53.893Z ddeb01ae-c9f6-40b2-ace5-b8b47ed21ebe INFO About to launch POST request
2020-09-09T20:15:54.644Z ddeb01ae-c9f6-40b2-ace5-b8b47ed21ebe INFO Resources destroyed.
END RequestId: ddeb01ae-c9f6-40b2-ace5-b8b47ed21ebe
REPORT RequestId: ddeb01ae-c9f6-40b2-ace5-b8b47ed21ebe Duration: 753.89 ms Billed Duration: 800 ms Memory Size: 128 MB Max Memory Used: 93 MB
Change the else if block as follows,
else if (obj.requestStatus === "finished") {
// This code will be scheduled to run after EXPIRATION_TIME
setTimeout(async () => {
let data = new FormData();
data.append("token", DESTROY_TOKEN);
data.append("ref", "terraform-v1");
data.append("variables[LAST_PIPELINE_ID]", pipelineId);
config = {
method: "POST",
url: `https://gitlab.com/api/v4/projects/${PROJECT_ID_DESTROY}/trigger/pipeline`,
data: data,
headers: {
...data.getHeaders(),
},
};
await axios(config).then(
() => {
console.log("Resources destroyed.");
},
(error) => {
console.log(`error : ${error}`);
}
);
}, EXPIRATION_TIME);
res.status(200);
res.json({ ec2Link: obj.ec2InstanceLink });
}
}
Note that EXPIRATION_TIME is in milliseconds.

How can I use slack api in aws lambda?

I want to use IncomingWebhook api of #slack/client in aws lambda function. There is something problems in my code. Please notice me how can I use.
This is my code below
const { IncomingWebhook } = require('#slack/client');
const config = require('./config')
exports.handler = (event, context, callback) => {
const webhook = new IncomingWebhook(config.slack.webHookUrl)
webhook.send('Hello there', function(err, res) {
if (err) {
console.log('Error:', err);
context.fail('fail')
} else {
console.log('Message sent: ', res);
context.succeed('succeed')
}
});
}
And This is my errors
{
"errorMessage": "RequestId: 9e1b4362-259d-11e8-b422-91108e46ebe1
Process exited before completing request"
}
Here is console errors
START RequestId: 9e1b4362-259d-11e8-b422-91108e46ebe1 Version: $LATEST
2018-03-12T02:32:33.215Z 9e1b4362-259d-11e8-b422-91108e46ebe1 TypeError: Cannot set property 'text' of undefined
at IncomingWebhook.send (/var/task/node_modules/#slack/client/dist/IncomingWebhook.js:26:26)
at exports.handler (/var/task/index.js:6:11)
END RequestId: 9e1b4362-259d-11e8-b422-91108e46ebe1
REPORT RequestId: 9e1b4362-259d-11e8-b422-91108e46ebe1 Duration: 85.31 ms Billed Duration: 100 ms Memory Size: 128 MB Max Memory Used: 31 MB
RequestId: 9e1b4362-259d-11e8-b422-91108e46ebe1 Process exited before completing request
This was due to a bug in the Slack client which was reported here: https://github.com/slackapi/node-slack-sdk/issues/479, and subsequently fixed in https://github.com/slackapi/node-slack-sdk/releases/tag/v4.0.1. A simple upgrade to the latest version (v4.3.1 at the time of writing) will fix this.

AWS Lambda and Redis

I'm trying to write an AWS Lambda function which uses redis(on amazon elasticcache). The problem – I can't connect to redis. I use code like this
'use strict'
function handler (data, context, cb) {
const redis = require("redis")
console.log('before client initialization')
const client = redis.createClient({
url: 'redis://propper-url-cache.some.0001.euw1.cache.amazonaws.com:6379',
retry_strategy: function(options) {
console.log(options)
if (options.total_retry_time > 1000) {
throw new Error('can`t connect to redis')
}
}
})
console.log('after client initialization')
client.on("error", function (err) {
console.log('in error')
cb({error: err})
});
client.get("counter", function (err, counter) {
console.log('counter', counter)
if(_.isNull(counter)) {
counter = 0
}
client.set('counter', counter + 1, function(err) {
console.log(err)
cb(null, {counter: counter})
})
});
}
exports.handler = handler
as a result I see something like this in logs:

15:33:41
START RequestId: d8024ec2-7f36-11e6-996c-1bfcb60572c6 Version: $LATEST

15:33:42
2016-09-20T13:33:42.632Z d8024ec2-7f36-11e6-996c-1bfcb60572c6 before client initialization

15:33:42
2016-09-20T13:33:42.813Z d8024ec2-7f36-11e6-996c-1bfcb60572c6 after client initialization

15:33:44
END RequestId: d8024ec2-7f36-11e6-996c-1bfcb60572c6

15:33:44
REPORT RequestId: d8024ec2-7f36-11e6-996c-1bfcb60572c6 Duration: 3002.67 ms Billed Duration: 3000 ms Memory Size: 128 MB Max Memory Used: 19 MB

15:33:44
2016-09-20T13:33:44.620Z d8024ec2-7f36-11e6-996c-1bfcb60572c6 Task timed out after 3.00 seconds
when I change redis url for something which definitely makes no sense I have an additional row:
2016-09-20T13:29:42.953Z 48fcb071-7f36-11e6-bc52-c5ac58c12843 { attempt: 1, error: { [Error: Redis connection to some-url.euw1.cache.amazonaws.com:6379 failed - getaddrinfo ENOTFOUND some-url.euw1.cache.amazonaws.com some-url.euw1.cache.amazonaws.com:6379] code: 'ENOTFOUND', errno: 'ENOTFOUND', syscall: 'getaddrinfo', hostna
Any ideas?
You need to have Redis in same VPC as Lambda. Check your security group settings. And then if you have EC2 access, install redis-cli and try to connect Redis. If this get connected your Lambda Redis will also get connected. As said earlier, you need to have your lambda in same VPC.
The following is boilerplate code demonstrating connecting to Lambda:
console.log('before client initialization')
const redisOptions = {
host: 'xxxx.xxx.xxx.xxx.xxx.amazonaws.com',
port: 6379,
}
var client = redis.createClient(redisOptions);
console.log('after client initialization');
client.on('connect', function(result) {
console.log('connected');
}

AWS Lambda function never calls the callback

I've created a node lambda function that does a simple call to an Aurora database. When I test the function in the console, the query returns, I can see the results in the log, but the callback never seems to get called and so my lambda function times out. I can't figure out what the problem is. Hopefully someone here can point me to the problem.
var mysql = require("mysql");
module.exports.handler = function(event, context, cb) {
console.log('start\n');
var con = mysql.createConnection({
...
});
console.log('call data\n');
con.query('SELECT * FROM Tags', function(err, rows) {
console.log('Data received from Db:\n');
console.log(rows);
console.log('calling callback');
cb(null, 'Success');
console.log('callback called');
});
console.log('data called\n');
};
The resulting Cloudwatch log is as follows...
2016-07-25T14:20:05.343Z daf5cd6b-5272-11e6-9036-e73ad17006df start
2016-07-25T14:20:05.398Z daf5cd6b-5272-11e6-9036-e73ad17006df call data
2016-07-25T14:20:05.405Z daf5cd6b-5272-11e6-9036-e73ad17006df data called
2016-07-25T14:20:05.440Z daf5cd6b-5272-11e6-9036-e73ad17006df Data received from Db:
2016-07-25T14:20:05.440Z daf5cd6b-5272-11e6-9036-e73ad17006df [
RowDataPacket {
id: 1,
externalId:
'a87ead34de7e',
orgId: 1,
name: 'lacinia sapien',
createdDate: 1448598369,
modifiedDate: 0
},
...,
RowDataPacket {
id: 50,
externalId: '9ebaaab372e3',
orgId: 1,
name: 'et commodo',
createdDate: 1451551837,
modifiedDate: 0
}
]
2016-07-25T14:20:05.483Z daf5cd6b-5272-11e6-9036-e73ad17006df calling callback
2016-07-25T14:20:05.483Z daf5cd6b-5272-11e6-9036-e73ad17006df callback called
END RequestId: daf5cd6b-5272-11e6-9036-e73ad17006df
REPORT RequestId: daf5cd6b-5272-11e6-9036-e73ad17006df Duration: 300000.12 ms Billed Duration: 300000 ms Memory Size: 1024 MB Max Memory Used: 52 MB
2016-07-25T14:25:05.341Z daf5cd6b-5272-11e6-9036-e73ad17006df Task timed out after 300.00 seconds
Thanks to this question...
Lambda Timing out after calling callback
I found the problem. the Node mysql module keeps the connection open until the server closes it unless it is explicitly closed by the handler logic.
So the node event loop never empties and so never returns the callback. In the above code, I did a ...
con.end();
before calling the callback and it worked.

Resources