Unable to get AWS Lambda to send message to an SQS Queue - amazon-web-services

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

Related

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.");
});
};

Publishing SNS message from lambda (node js) result in timeout error

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.

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:

How to get the attributes of an added item in DynamoDB using Lambda function

I have an AWS Lambda function which is being triggered by AWS DynamoDB. The function checks if the operation in the DB is INSERT, and if it does, then it sends a new push message using AWS SNS:
console.log('Loading function');
var AWS = require('aws-sdk');
AWS.config.region = 'us-east-1';
exports.handler = function(event, context, callback) {
console.log("\n\nLoading handler\n\n");
var sns = new AWS.SNS();
console.log(JSON.stringify(event, null, 2));
event.Records.forEach(function(record) {
if (record.eventName == "INSERT") {
sns.publish({
Subject: 'Test',
Message: 'Test publish to SNS from Lambda',
TopicArn: 'TOPIC-ARN'
}, function(err, data) {
if (err) {
console.log(err.stack);
return;
}
console.log('push sent');
console.log(data);
context.done(null, 'Function Finished!');
});
}
});
callback(null, "message");
};
Is there a way that I could get the attributes of the newly added item?
var id = record.dynamodb.Keys.Id.N;

Amazon Lambda to SNS notifications not working

I have a use case of pushing SNS notifications from Amazon lambda. I have written the following code, with the IAM role having the permission to invoke SNS. Even with the Kenesis trigger, this Lambda function is unable to send any notification to SNS. I confirmed this by, subscribing my email id to the SNS.
[EDIT]: Just a follow up question. I now need to query DynamoDB and based on the output, need to call different end point of SNS. Now, when I query DynamoDB, the execution stops after DynamoDB query and not even progressing for SNS checks.
Following is my lambda function code.
console.log('Loading function');
var AWS = require('aws-sdk');
exports.handler = function(event, context) {
event.Records.forEach(function(record) {
//var payload = new Buffer(record.kinesis.data, 'base64').toString('ascii');
var payload = record.kinesis.data;
console.log('Decoded payload:', payload);
var dynamodb = new AWS.DynamoDB();
var dynamodb_params = {
Key: {
dataSource: {
S: payload
}
},
TableName: 'TableName',
AttributesToGet: [
'attribute' // ...
],
ConsistentRead: false,
};
var sns_endpoint = null;
dynamodb.getItem(dynamodb_params, function(err, data) {
if (err) {
console.log(err.stack);
context.done(err, 'Errors while querying dynamodb!');
} else {
console.log(data);
sns_endpoint = data.Item.sns.S;
console.log("Result= " + data);
console.log("Item= " + data.Item);
console.log("sns= " + data.Item.sns);
console.log("value= " + data.Item.sns.S);
console.log("sns_endpoint= " + sns_endpoint);
context.done(null, 'Querying dynamodb succeeded!');
}
});
if( sns_endpoint != null ) {
console.log("sns_endpoint= " + sns_endpoint);
var sns_params = {
Message: payload,
Subject: 'Event Notification From Lambda',
TopicArn: sns_endpoint
};
var sns = new AWS.SNS();
sns.publish(sns_params, function(err, data) {
if (err) {
console.log(err.stack);
context.done(err, 'Errors while putting to SNS!');
} else {
console.log(data);
context.done(null, 'Putting to SNS succeeded!');
}
});
}
});
};
You are calling an asynchronous function, sns.publish(), within a forEach loop. Then you are immediately calling context.succeed(). As soon as context.succeed, context.fail or context.done are called, your Lambda function will exit. You need to modify your code to only call one of those after all asynchronous function calls have completed.