Node JS AWS SQS only receiving one message - node.js

I have 3 messages at my aws message inbox. But i am only getting one message when I'm trying
to retrieve all. I am getting only the last message, but the other two messages are not showing.
Here is my code:
const AWS = require("aws-sdk");
AWS.config.update({ region: "REGION" });
const sqs = new AWS.SQS({ apiVersion: "2012-11-05" });
const readMessage = function () {
const params = {
MaxNumberOfMessages: 10,
QueueUrl: "https://sqs.us-east-1.amazonaws.com/56622448/my-queue",
};
sqs.receiveMessage(params, function (err, data) {
if (err) {
console.log("Error", err);
} else if (data.Messages) {
console.log(data);
}
});
};
readMessage();
This is the output:
{
ResponseMetadata: { RequestId: 'a9e53cee-afc8-57c-664408f1e602' },
Messages: [
{
MessageId: 'bb3e23f9-07fd-4205-9b53-a48f826',
ReceiptHandle: 'AQEBD6rCOZlaBfCNn3nU4AEE7OlYwFJFeblTaiDoxIy8HiwsjdxZX+3SICY/YW5PI+RuFscMMh6VyExoo1i8Zo2JlbYj3t32b9CXnToYugzBqgZuxuYOTzXRAnrGwlavSL7hcLQvW6y8me1gnj65N3tPYEmcfXX5GIiQTn1yNEou3rUNff9DfkSije/0zvp33yfWfcW+RDzB2y6ND6eKHxfsP/cqmHjRaT0bE9rlXorjgh36YwVJ57e5bjUa/1dVqOf3ybXfEX/5C2eZM+T1V2JBxlguvuL1B3aHKAC+R9Pdgpdg2kmK3+bVmOxbQJKfU0s3sD9fElZJmLuLLMPb835z5hbVv44fKJVuEc7ad2uL3d1AUCbq3MKRCb38t77L4Ifa/ob3QQ==',
MD5OfBody: '7b84813a4b4bf10f0edb9e8da7',
Body: "Handsome Person Basic Information."
}
]
}
My Expected Output:
{
ResponseMetadata: { RequestId: 'a9e53cee-afc8-57c-664408f1e602' },
Messages: [
{
MessageId: 'bb3e23f9-07fd-4205-9b53-a48f826',
ReceiptHandle: 'AQEBD6rCOZlaBfCNn3nU4AEE7OlYwFJFeblTaiDoxIy8HiwsjdxZX+3SICY/YW5PI+RuFscMMh6VyExoo1i8Zo2JlbYj3t32b9CXnToYugzBqgZuxuYOTzXRAnrGwlavSL7hcLQvW6y8me1gnj65N3tPYEmcfXX5GIiQTn1yNEou3rUNff9DfkSije/0zvp33yfWfcW+RDzB2y6ND6eKHxfsP/cqmHjRaT0bE9rlXorjgh36YwVJ57e5bjUa/1dVqOf3ybXfEX/5C2eZM+T1V2JBxlguvuL1B3aHKAC+R9Pdgpdg2kmK3+bVmOxbQJKfU0s3sD9fElZJmLuLLMPb835z5hbVv44fKJVuEc7ad2uL3d1AUCbq3MKRCb38t77L4Ifa/ob3QQ==',
MD5OfBody: '7b84813a4b4bf10f0edb9e8da7',
Body: "Handsome Person Basic Information."
},
{
Body: "Handsome Person Basic Information II"
},
{
Body: "Handsome Person Basic Information III"
}
]
}
Under messages, i should be getting three. but retrieving is only one message.
Take note: I have just short cut the value of my expected value just to prove my point.
How would I able to get all of the three messages? Thanks !

This is the default behavior of AWS SQS
"If the number of messages in the queue is small (fewer than 1,000), you most likely get fewer messages than you requested per ReceiveMessage call. If the number of messages in the queue is extremely small, you might not receive any messages in a particular ReceiveMessage response. If this happens, repeat the request. "
Class ReceiveMessageCommand
Long polling might help, but not guarantee you will receive all message at once

Long polling is the solution. You can achieve by 2 ways :
Recall your "readMessage()" recursively(I won't recommend to use setInterval)
Use npm SQS-consumer

Related

AWS Lambda: "Cannot read property '0' of undefined"

Here is my AWS Lambda function. However, when running it, I get Cannot read property '0' of undefined.
const AWS = require('aws-sdk');
const SES = new AWS.SES();
const FROM_EMAIL_ADDRESS = process.env.FROM_EMAIL_ADDRESS;
const TO_EMAIL_ADDRESS = process.env.TO_EMAIL_ADDRESS;
function sendEmailToMe(formData) {
const emailParams = {
Source: FROM_EMAIL_ADDRESS,
ReplyToAddresses: ['keshijemi478#gmail.com'],
Destination: {
ToAddresses: [TO_EMAIL_ADDRESS],
},
Message: {
Body: {
Text: {
Charset: 'UTF-8',
Data: `Thanks for subscribe: ${formData.message}\n\n Name: ${formData.name}\n Email: ${formData.email}\n I will reply as soon as possible`,
},
},
Subject: {
Charset: 'UTF-8',
Data: 'New message from your_site.com',
},
},
};
console.log(emailParams);
const promise = SES.sendEmail(emailParams).promise();
console.log(promise);
return promise;
}
exports.handler = async(event) => {
console.log('SendEmail called');
const dynamodb = event.Records[0].dynamodb;
console.log(dynamodb);
const formData = {
name : dynamodb.NewImage.name.S,
message : dynamodb.NewImage.message.S,
email : dynamodb.NewImage.email.S
};
console.log(formData);
return sendEmailToMe(formData).then(data => {
console.log(data);
}).catch(error => {
console.log(error);
});
};
It appears that your code is an AWS Lambda function.
When a Lambda function is called, information is passed to the function via the event parameter. The information passed via event varies depending upon how the function was triggered. For example, if the function is triggered by an Amazon S3 Event, then S3 provides information in the event parameter that describes the object that caused the event to be triggered.
If, however, you trigger this event 'manually', then Amazon S3 is not involved and the event parameter only contains the information that you provided when you invoked the function.
If you are testing the function in the AWS Lambda management console, you can supply an event via the "Configure Test" option. The event provided in this configuration will then be passed to the function being tested.

Twilio programmable SMS not sending in deployed Lambda function

I am working on a Serverless AWS service that uses Twilio's programmable SMS to deliver text messages.
My setup is consistently delivering messages successfully when I run the stack locally (e.g. sls offline start), but in the deployed environment I seem to be unable to even call the method on the Twilio client.
Here's how the message delivery is set up:
const twilio = require('twilio');
const twilioClient = twilio(
process.env.TWILIO_SID,
process.env.TWILIO_TOKEN,
{
lazyLoading: true,
}
);
export function sendMessage(user, message) {
twilioClient.messages.create({
from: process.env.TWILIO_NUMBER,
to: user.phone,
body: message,
}, function(err, message) {
console.log('error', err);
console.log('message', message);
});
}
// And then usage in a Serverless Function Handler
function example(event, context, callback) {
context.callbackWaitsForEmptyEventLoop = false;
// user is also determined here
sendMessage(user, 'This is a message');
return {
body: JSON.stringify({}),
statusCode: 200
};
}
Locally, running this works and I am able to see the output of the message log, with nothing on the error log. However, when deployed, running this yields nothing -- the method appears to not even get called (and I can verify in the Twilio logs that no API call was made), therefor no error or message logs are made in the callback.
In debugging I've tried the following:
I've logged all the environment variables (Twilio SSID, auth token, phone number), as well as the function arguments, and they all appear to be in place. I also checked out the Lambda function itself to make sure the environment variables exist.
I've examined my CloudWatch logs; no errors or exceptions are logged. Other than the Twilio method not getting called the Lambda function is executed without issue.
I've tried logging things like twilio and twilioClient.messages.create to make sure the client and function definition didn't get wiped out somehow.
I thought maybe it had to do with context.callbackWaitsForEmptyEventLoop so I changing it from false to true.
I have come up empty, I can't figure out why this would be working locally, but not when deployed.
Edit: per the Twilio client example, if you omit the callback function the method will return a Promise. I went ahead and tried to await the response of the method:
export function sendMessage(user, message) {
return twilioClient.messages.create({
from: process.env.TWILIO_NUMBER!,
to: user.phone,
body: message,
});
}
// Usage...
async function example(event, context, callback) {
context.callbackWaitsForEmptyEventLoop = false;
try {
const message = await sendMessage(user, 'This is a message');
console.log('message', message)
} catch (error) {
console.log('error', error);
}
return {
body: JSON.stringify({}),
statusCode: 200
};
}
In this example the Lambda function is successful, but neither the message nor the error are logged.
I tried this and it works. I tried to make my code as similar to use, with a few changes.
const twilio = require('twilio');
const twilioClient = twilio(
process.env.TWILIO_SID,
process.env.TWILIO_TOKEN
);
let user = '+14075551212';
function sendMessage(user, message) {
return twilioClient.messages.create({
from: process.env.TWILIO_NUMBER,
to: user,
body: message,
});
}
exports.handler = async function(event, context, callback) {
try {
const message = await sendMessage(user, 'This is a message');
console.log('message', message);
callback(null, {result: 'success'});
} catch (error) {
console.log('error', error);
callback("error");
}
};

Getting list of messages from Twilio with pagenation

I want to get all the messages from my twilio account.
I tried this code
var client = new twilio(twilioConfig.accountSid, twilioConfig.authToken);
client.messages.list({ Page: 0, PageSize: 10 }, function (err, data) {
console.log(data);
res.send({ message: "Success" });
});
in this code getting all messages, i need 10 per page
Twilio developer evangelist here.
If you are using the latest version of the Twilio Node module then you can get all your messages in a couple of ways.
You can call each on the message list object which lazily streams the messages.
const client = require('twilio')(YOUR_ACCOUNT_SID, YOUR_AUTH_TOKEN);
client.messages.each({ pageSize: 10 }, function(message) {
console.log(message);
});
Or you can call list on the message list, which eagerly loads all of the messages.
client.messages.list({ pageSize: 10 }, function(messages) {
messages.forEach(function(message) {
console.log(message);
});
});
You can also use page and subsequently nextPage to manually page through all of the messages.
client.messages.page({ pageSize: 10 }, function pageReceived(page) {
page.instances.forEach(function(message) {
console.log(message);
});
if (page.nextPage) {
page.nextPage().then(pageReceived);
}
})
Let me know if any of that helps at all.

ses.sendMail() inside a aws lambda function not returning callback

Amazon Simple Email Service (Amazon SES)
I have the below code. It works perfectly if I use it from an aws ec2 instance or from my workstation. But as soon as I add it to a lambda function I am working on inside of an AWS VPC, the callback to my ses.sendEmail() never gets called. I never see a "sendEmail Function Error", or a "sendEmail Function Success" console.log() in my CloudWatch Logs for the function and my lambda function times out at the end of my timeout period. I don't know what more I can do.
I have looked for any IAM roles or policies that I might have to add, can't find any mention of them needed, or which ones to add.
Tried adding the Policy 'AmazonSESFullAccess' to my IAM role for the function. Still Times out.
let aws = require('aws-sdk')
, ses = new aws.SES({ apiVersion: '2010-12-01', region: 'us-west-2' })
;
sendEmail({
To : [ 'anEmail#someone.com' , 'anotherEmail#somewhereElse.com'],
From: 'ourSupportEmail#whereIWork.com',
Subject: 'Sending An Email Out',
Body: `<html> A Buch of HTML Here</html>`
}, function(err, result){
if(err){
console.error('SendEmail Error', err);
} else {
console.log('SendEmail Result', result);
}
});
function sendEmail(emailObj, cb){
emailObj.To.push('myEmail#whereIWork.com');
let mailData = {
Source: emailObj.From,
Destination: { ToAddresses: emailObj.To },
Message: {
Subject: {
Data: emailObj.Subject
},
Body: {
Html: {
Data: emailObj.Body
}
}
}
}
console.log('sending Email', JSON.stringify(mailData)); //see in Cloudwatch Logs! YEAH!!!
ses.sendEmail(mailData, function(err, data){
if(err){
console.log('sendEmail Function Error', JSON.stringify(err)); // never see in cloudwatch logs, WHAT??
cb(err);
} else {
console.log('sendEmail Function Success', JSON.stringify(data)); // never see in cloudwatch logs, WHAT??
cb(null, data);
}
});
}
You're lambda is set up inside a VPC, which in that case - has no access to the internet, thus no access to AWS APIs as well.
If you let your lambda run long enough - the callback will be called with a connection timeout error.
Please follow my detailed answer here.

Facebook Messenger bot not sending messages in order

I'm playing around with building a simple Facebook Messenger chatbot and I'm having trouble sending messages in sequence.
In the example above, it should have printed "Hello!", "1", "2", "3" in order. I'm currently following the Facebook docs found here to implement this simple text message function. I've included my Express Node.JS server code below:
Defining the sendTextMessage() function:
var request = require("request");
function sendTextMessage(user, text) {
messageData = {
text: text
};
request({
url: "https://graph.facebook.com/v2.6/me/messages",
qs: {access_token: PAGE_ACCESS_TOKEN},
method: "POST",
json: {
recipient: {id: user},
message: messageData
}
}, function(error, response, body) {
if (error) {
console.log("Error sending message: ", error);
} else if (response.body.error) {
console.log("Error: ", response.body.error);
} else {
console.log("Message successfully send.")
}
});
}
Using it to send a response:
sendTextMessage(user, "Hello!");
sendTextMessage(user, "1");
sendTextMessage(user, "2");
sendTextMessage(user, "3");
I even tried implementing a simple queue that queues messages and only sends one message at a time after each request's success callback. This is making me suspect that I'm not interacting with the Messenger API correctly.
Has anyone encountered this issue? How can I get messages to send in sequence? Thanks!
EDIT
Because I implemented a simple queue but still experiencing this problem, I'm including the code for my simple queue system here.
var queue = [];
var queueProcessing = false;
function queueRequest(request) {
queue.push(request);
if (queueProcessing) {
return;
}
queueProcessing = true;
processQueue();
}
function processQueue() {
if (queue.length == 0) {
queueProcessing = false;
return;
}
var currentRequest = queue.shift();
request(currentRequest, function(error, response, body) {
if (error || response.body.error) {
console.log("Error sending messages!");
}
processQueue();
});
}
queueRequest(/* Message 1 */);
queueRequest(/* Message 2 */);
queueRequest(/* Message 3 */);
UPDATE
This "bug" was reported to Facebook but it sounds like they aren't going to fix it. Please read the ticket thread on Facebook's post here for details on what they say is going on. (Thank you to Louise for getting Facebook's attention on this)
I submitted a bug report to Facebook about this because I was having the same problem. They acknowledged that it is indeed a bug and are working to fix it: https://developers.facebook.com/bugs/565416400306038
After you send a POST to /me/messages, you'll receive a response that has a message id (mine start with 'mid.' which maybe stands for message id?):
{ recipient_id: '1015411228555555',
message_id: 'mid.1464375085492:b9606c00ca33c12345' }
After being completely received by the FB Messenger API, you'll get a call to your webhook (with no message events) that confirms receipt:
{ sender: { id: '1015411228555555' },
recipient: { id: '566031806XXXXXX' },
delivery:
{ mids: [ 'mid.1464375085492:b9606c00ca33c12345' ],
watermark: 1464375085604,
seq: 176 } }
I think that delivery receipt is the best way to ensure delivery, then send the next message.
Implement the send request as a Promise and only send consequent messages once the previous one is resolved
const send = (userId, messageData) => {
return new Promise((resolve, reject) => {
request
(
{
url : BASE_URL + "me/messages",
qs : { access_token : PAGE_ACCESS_TOKEN },
method : "POST",
json :
{
recipient: { id : userId },
message: messageData,
}
}, (error, response, body) =>
{
if (error) { console.log("Error sending message: " + response.error); return reject(response.error); }
else if (response.body.error) { console.log('Response body Error: ' + response.body.error); return reject(response.body.error); }
console.log("Message sent successfully to " + userId);
return resolve(response);
}
);
});
};
You can achieve QUEUING by promises.
function delay(time) {
return new Promise(function(resolve, reject) {
setTimeout(resolve, time);
});
}
delay(2000).then(() => {
console.log('hi');
delay(2000).then(() => {
console.log('hello');
delay(2000).then(() => {
console.log('welcome');
})
})
})
Instead of adding static timeouts, I would create a queue data structure. When the bot wants to send a message, append the contents to the end of the queue. On the message post callback, check if there are any messages still in the queue and call the function again using recursion and remove from the queue accordingly.
They should be received in the order that they are sent. Make sure you're actually sending them in order and not calling an async function 4 times (and send order isn't guaranteed). (I read that you tested it but in all my testing I've never seen a receive come out of order if the send order was guaranteed.)
I added a messageId counter to the app that resets to 0 on every start of messagehandling. Then I delay with that number * 100 ms. This way I can add intentional delays as well with code like messageDelay += 15
receivedMessage(event) {
messageDelay = 0;
//...
sendMessage extend:
function sendTextMessage(recipientId, messageText) {
//...
setTimeout(function() {
callSendAPI(messageData);
}, messageDelay++ * 100)
}
The message is not sending in order because, the request is sent asynchronously to facebook, and can be sent in any order.
To solve this you have to call the next sendTextMessage when the message that should be sent before it has received a response.
Based on the recursive solution proposed by #user3884594, I kind of make it work using this (I removed the error handling in order to simplify):
send_messages (["message 01", "message 02", "message 03"]);
function send_messages (which, i = 0)
{
request({
url: 'https://graph.facebook.com/v2.10/me/messages',
qs: { access_token: FACEBOOK_ACCESS_TOKEN },
method: 'POST',
json: { recipient: { id: senderId }, message: { text: which [i] }
}, (error, response, body) =>
{
// You need to put your error handling logic here
if (i++ < which.length - 1)
send_messages (which, i);
});
}
I had exactly same problem, that solution worked for me:
function sendMessage(recipient, messages, accessToken, i) {
axios.post(baseURL + 'v2.11/me/messages/?access_token=' + accessToken,
Object.assign({}, {
messaging_type: "RESPONSE",
recipient: {
id: recipient
}
}, messages[i]['payload']) )
.then(response => {
if(i < messages.length) sendMessage( recipient, messages, accessToken, i+1 );
},
error => {})
.catch(error => {});
}
sendMessage(recipient, flow['messages'], flow['page']['accessToken'], 0);
That's my question: Sequential Message Sending Using Facebook Send-API
You can try putting them inside a setTimeout function so each one goes after a certain period of time.
So replace this:
sendTextMessage(user, "Hello!");
sendTextMessage(user, "1");
sendTextMessage(user, "2");
sendTextMessage(user, "3");
With this:
sendTextMessage(user, "Hello!");
// 1 second
setTimeout(function() {
sendTextMessage(user, "1");
}, 1000)
// 2 seconds
setTimeout(function() {
sendTextMessage(user, "2");
}, 2000)
// 3 seconds
setTimeout(function() {
sendTextMessage(user, "3");
}, 3000)
And they should go one after another. You could also embed the functions inside each other if need be.

Resources