Publishing SNS message from lambda (node js) result in timeout error - amazon-web-services

I have used a very simple code slightly modified from AWS provided example:
exports.handler = async (event) => {
// Load the AWS SDK for Node.js
var AWS = require('aws-sdk');
// Set region
AWS.config.update({region: 'ap-southeast-2'});
// Create publish parameters
var params = {
Message: 'This is a sample message',
Subject: 'Test SNS From Lambda',
TopicArn: 'arn:aws:sns:ap-southeast-2:577913011449:TestTopic'
};
// Create promise and SNS service object
var publishTextPromise = new AWS.SNS().publish(params).promise();
let response = {
statusCode: 200,
body: JSON.stringify('Hello from Lambda!'),
};
// Handle promise's fulfilled/rejected states
publishTextPromise.then(
function(data) {
console.log("Message ${params.Message} send sent to the topic ${params.TopicArn}");
console.log("MessageID is " + data.MessageId);
response.result = 'Success';
}).catch(
function(err) {
console.error(err, err.stack);
response.result = 'Error';
});
return response;
};
And I am getting a timeout error when testing this service. 3 seconds is the limit.
Since this is a very simply process, I suppose it shouldn't take more than 3 seconds to execute.
I have checked my IAM setting and grant my profile (admin profile) to have full access to SNS service. But the error still persists. I am wondering what is being wrong here and how should I fix this?

I am not sure why you're getting the timeout, but your code isn't supposed to work the way you might expect.
See that you're returning your response outside your .then() code, meaning that your code is going to return before your .then() code is even run (Promises are asynchronous).
Since you're already using Node 8, you're better off using async/await instead of using the old .then().catch() approach.
I have refactored your code a little bit and it works just fine. I have kept the original parameters for your convenience. See how the code is much easier to read and debug.
'use strict';
// Load the AWS SDK for Node.js
const AWS = require('aws-sdk');
// Set region
AWS.config.update({region: 'ap-southeast-2'});
const sns = new AWS.SNS()
module.exports.handler = async (event) => {
const params = {
Message: 'This is a sample message',
Subject: 'Test SNS From Lambda',
TopicArn: 'arn:aws:sns:ap-southeast-2:577913011449:TestTopic'
};
let response = {
statusCode: 200,
body: JSON.stringify('Hello from Lambda!'),
};
try {
const data = await sns.publish(params).promise();
response.messageId = data.MessageId,
response.result = 'Success'
} catch (e) {
console.log(e.stack)
response.result = 'Error'
}
return response
};
If for whatever reason you don't want to use async/await, you then need to move the return of your function inside your .then() code, as well as return as soon as the promise is invoked, like this:
'use strict';
// Load the AWS SDK for Node.js
var AWS = require('aws-sdk');
// Set region
AWS.config.update({region: 'ap-southeast-2''});
// Create publish parameters
var params = {
Message: 'This is a sample message',
Subject: 'Test SNS From Lambda',
TopicArn: 'arn:aws:sns:ap-southeast-2:577913011449:TestTopic'
};
module.exports.handler = async (event) => {
// Create promise and SNS service object
var publishTextPromise = new AWS.SNS().publish(params).promise();
let response = {
statusCode: 200,
body: JSON.stringify('Hello from Lambda!'),
};
// Handle promise's fulfilled/rejected states
return publishTextPromise.then(
function(data) {
console.log("Message ${params.Message} send sent to the topic ${params.TopicArn}");
console.log("MessageID is " + data.MessageId);
response.result = 'Success';
return response;
}).catch(
function(err) {
console.error(err, err.stack);
response.result = 'Error';
return response
});
};
I highly recommend you go with approach #1 though.

Related

AWS SDK - Writing a lambda to get all roles for the current account

Working on writing a lambda to get all IAM roles within the current account using the AWS SDK documentation provided for Javascript: https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/IAM.html
However, my lambda keeps returning a null value, whereas I'm expecting it to return a list of existing roles in the response body:
const AWS = require("aws-sdk");
exports.handler = async (event) => {
var iam = new AWS.IAM();
var roles = [];
iam.listRoles(function(err, data) {
if (err) console.log(err, err.stack); // an error occurred
else roles.push(data); // successful response
const response = {
statusCode: 200,
body: JSON.stringify(roles)
};
return response;
});
};
I'm obviously missing something here. Any insights would be appreciated.
You are using an Old version of the AWS SDK for JavaScript. That doc you referenced is not the latest.
Try using the latest version as described in this AWS SDK for JavaScript DEV Guide V3 here:
https://docs.aws.amazon.com/sdk-for-javascript/v3/developer-guide/iam-examples-managing-users.html
The problem is mixing up the async and callback, you can use promise to handle listRoles.
const AWS = require('aws-sdk');
exports.handler = async event => {
try {
const iam = new AWS.IAM();
const roles = await iam.listRoles().promise();
return {
statusCode: 200,
body: JSON.stringify(roles)
};
} catch (err) {
console.log(err, err.stack);
return {
statusCode: 200, // might change to error code here
body: []
};
}
};

Unable to get AWS Lambda to send message to an SQS Queue

Unable to get AWS Lambda to send message to an SQS Queue. I have removed the ids from the queue URL. The code doesn't fail but also doesn't send any message.
var AWS = require('aws-sdk');
exports.handler = async (event) => {
process.env['AWS_ACCESS_KEY_ID'] = process.env['AWS_ACCESS_KEY_ID_VAL'];
process.env['AWS_SECRET_ACCESS_KEY'] = process.env['AWS_SECRET_ACCESS_KEY_VAL'];
process.env['AWS_REGION'] = process.env['AWS_REGION_VAL'];
console.log("11")
AWS.config.update({region: 'ap-southeast-2'});
// Create an SQS service object
var sqs = new AWS.SQS({apiVersion: '2012-11-05'});
console.log("22")
var params = {
MessageBody: "This is a test message",
QueueUrl: "https://sqs.ap-southeast-2.amazonaws.com/11111111111/the-queue-name"
};
console.log("33")
var outcome = await sqs.sendMessage(params, await function(err, data) {
console.log("logging here")
if (err) {
console.log("Error", err);
} else {
//Log successful result id
console.log("Success", data.MessageId);
}
});
};
You will need promise() at the end of await sqs.sendMessage like this:
await sqs.sendMessage(
...
).promise();
Ref:
Example index.js file – AWS SDK with async handler and promises
https://docs.aws.amazon.com/lambda/latest/dg/nodejs-handler.html#nodejs-handler-async

How to publish to a particular Mobile push notification endpoint from Lambda?

I have a SNS mobile push notification service configured in AWS with FCM. I am able to send push notifications to a particular endpoint from the console with publish message.
But I want to publish a message to a particular endpoint from a Lambda function. I wrote a Lambda and gave necessary functions. But when I try to run the lambda there is no error thrown and no push notification actions.
Here is my code,
var AWS = require('aws-sdk');
var sns = new AWS.SNS();
exports.handler = async (event) => {
var params = {
TargetArn:'arn:aws:sns:eu-central-1:<my_user_id>:app/GCM/<my_sns_projectname>/<device-token>',
Message:'Success!!! ',
Subject: 'TestSNS'
};
await sns.publish(params , (err,data)=>{
if (err) {
console.log("Error sending a message " + err);
} else {
console.log("Sent message: " + data.MessageId);
}
})
};
I am a beginner, some help pls :)
Voila!! This worked for me!
var AWS = require('aws-sdk');
var sns = new AWS.SNS();
const params = {
TargetArn:'arn:aws:sns:eu-central-1:<my_user_id>:app/GCM/<my_sns_projectname>/<device-token>',
Message:JSON.stringify('Success!!! '),
Subject: 'TestSNS'
};
exports.handler = async (event, context, callback) => {
const publishPromise = sns.publish(params).promise();
await publishPromise.then((response) => {
console.log("SENT")
callback(null, "Message published.");
}, (err) => {
console.log("We had an error");
console.log(err);
callback("Message wasn’t able to publish.");
});
};

Lambda SDK Calls No Response

I am trying to do a pretty simple "hello world" in AWS Lambda. I tried a few services that only call the AWS SDK and just try to read. My callback never gets called. I have to be missing something. Any help appreciated!
var AWS = require("aws-sdk");
exports.handler = async (event) => {
// TODO implement
const response = {
statusCode: 200,
body: JSON.stringify('Hello from Lambda!'),
};
var s3 = new AWS.S3(); // confirmed this is not null
s3.listBuckets({}, function(err, data) {
// never reaches here!
if (err) console.log(err, err.stack); // an error occurred
else console.log(data); // successful response
});
return response;
};
I did create a role this lambda is using that has S3 access. :-)
It seems that because I chose the Node 8.x runtime, I needed to use one of those async constructs. This worked...
let AWS = require('aws-sdk');
let s3 = new AWS.S3();
exports.handler = async (event) => {
return await s3.listBuckets().promise() ;
};
This is a synchronization problem.
Your return response code is executed before your callback is invoked.
you'll have to put your return statement inside your callback or use async/await
Returning inside your callback:
var AWS = require("aws-sdk");
exports.handler = async (event) => {
const response = {
statusCode: 200,
body: JSON.stringify('Hello from Lambda!'),
};
var s3 = new AWS.S3();
s3.listBuckets({}, function (err, data) {
if (err) {
console.log(err, err.stack);
return {
statusCode: 500,
message: 'some error'
}
}
return response
});
}
Using async/await:
var AWS = require("aws-sdk");
exports.handler = async (event) => {
const response = {
statusCode: 200
};
var s3 = new AWS.S3();
await s3.listBuckets().promise();
return response;
}
I'd go with the async/await approach as it's much cleaner and more readable. It's also easier to work with promises than with callbacks.
EDIT: The OP claimed it didn't work. So I have decided to test it on my own. The above code works, with a very small change just to add the listed buckets to the response. Here's the final code:
var AWS = require("aws-sdk");
exports.handler = async (event) => {
const response = {
statusCode: 200
};
var s3 = new AWS.S3();
const buckets = await s3.listBuckets().promise();
response.body = JSON.stringify(buckets);
return response;
}
And here's the output in CloudWatch Logs:

Sending SNS push through lambda - no message?

I have a problem with my lambda function. It takes the data of the devices and sends the push notification (information that someone added you to friends). However, it often happens that the push notificaiton is not sent. Sometimes, I have to activate the function couple of times (through simultaneous clicking on the button) to make it send push notifications. When testing the below function in Lambda it does not send any push notifications. What might be the issue?
Thank you in advance,
John
console.log("Loading friend-request function");
var AWS = require("aws-sdk");
exports.handler = function(event, context) {
var senderID = event.senderID;
var receiverID = event.receiverID;
var message = event.message;
var eventText = JSON.stringify(event);
console.log("Received event:", eventText);
var sns = new AWS.SNS();
var params = {
Message: message,
Subject: "Test SNS From Lambda",
TargetArn: receiverID
};
context.succeed(message);
sns.publish(params, context.done);
};
Remember that the sns.publish() function is asynchronous, i.e. you must wait for it to complete before you can call the context.succeed(). Otherwise, the Lambda function may terminate before the message has been published.
exports.handler = function(event, context) {
// same as before...
var params = {...}
// do not call context.succeed() yet
sns.publish(params, function(err, data) {
if (err) {
console.log('Failed to publish SNS message');
context.fail(err);
}
else {
console.log('SNS message published successfully');
context.succeed(data);
}
});
};