Why does AWS Lambda function return null? - node.js

My AWS Lambda function sends an email through SNS, but the response is null in the Lambda console. I used a blueprint provided by AWS and put the code in a Lambda handler using Node.js 10.x.
https://github.com/awsdocs/aws-doc-sdk-examples/blob/master/javascript/example_code/sns/sns_publishtotopic.js
I am not that experienced in the use of promises in node.js and my research on Stack Overflow seems to indicate that could be the problem here.
'use strict';
var AWS = require('aws-sdk');
// Set region
AWS.config.update({region: 'us-west-2'});
exports.handler = (event, context, callback) => {
// Create publish parameters
var params = {
//Message: `The fluid level is low on your Knight system: ${event.my_volume} mL.`,
Message: `The fluid level is low on your Knight system.`,
Subject: `Low Fluid Level Alert - Knight`,
TopicArn: `arn:aws:sns:us-west-2:468820349153:MyLowVolumeTopic`,
};
// Create promise and SNS service object
var publishTextPromise = new AWS.SNS({apiVersion: '2010-03-31'}).publish(params).promise();
// Handle promise's fulfilled/rejected states
publishTextPromise.then(
function(data) {
console.log("Message: " + params.Message);
console.log("Sent to the topic: " + params.TopicArn);
console.log("MessageID is " + data.MessageId);
}).catch(
function(err) {
console.error(err, err.stack);
});
};
The result is that I receive the email message inconsistently and see a null response in the Lambda console. Here is a sample log result:
Response: null
Request ID: "9dcc8395-5e17-413a-afad-a86b9e04fb97"
Function Logs:
START RequestId: 9dcc8395-5e17-413a-afad-a86b9e04fb97 Version: $LATEST
2019-08-17T21:44:31.136Z 9dcc8395-5e17-413a-afad-a86b9e04fb97 Message: The fluid level is low on your Knight system.
2019-08-17T21:44:31.136Z 9dcc8395-5e17-413a-afad-a86b9e04fb97 Sent to the topic: arn:aws:sns:us-west-2:468820349153:MyLowVolumeTopic
2019-08-17T21:44:31.136Z 9dcc8395-5e17-413a-afad-a86b9e04fb97 MessageID is cb139fb6-5d37-574e-9134-ca642a49fde5
END RequestId: 9dcc8395-5e17-413a-afad-a86b9e04fb97
REPORT RequestId: 9dcc8395-5e17-413a-afad-a86b9e04fb97 Duration: 1367.98 ms Billed Duration: 1400 ms Memory Size: 128 MB Max Memory Used: 75 MB

Your lambda is exiting before completing the promise. To circumvent this you can use async-await:
exports.handler = async (event, context, callback) => {
const data = await publishTextPromise;
//maybe some console log here
return data;
}
OR, You can return the promise, return publishTextPromise.then(...).catch(...)

Related

Locally run Lambda would not log all outputs

I have the following Lambda.
const AWS = require('aws-sdk');
exports.lambdaHandler = async (event, context) => {
console.log("START v5");
const SNSarn = process.env.SNS;
console.log(SNSarn);
const snsParams={
Message: "test",
TopicArn: SNSarn
};
const SNS = new AWS.SNS();
SNS.publish(snsParams, function(err,data){
console.log ("We are in the callback!");
if (err) {
console.log('Error sending a message', err);
context.done(err,'We have errors');
}
console.log('Sent message');
context.done(null,"Done!");
});
console.log('END');
};
When I run it locally, ther lambda performs as expected and pushes a message to SNS.
For some reason, I do not see the console.log that is in the callback.
How do I fix it so I can also see logs from callbacks?
Below is the output I do see:
START RequestId: ff2691cc-a7d0-40f2-a956-277bxxxx21d Version: $LATEST
2021-11-15T21:17:17.968Z ff2691cc-a7d0-40f2-a956-277bxxxx821d INFO START v5
2021-11-15T21:17:17.970Z ff2691cc-a7d0-40f2-a956-277bxxxx821d INFO arn:aws:sns:us-east-1:xxxxxxxxxxxxxxx:tooktook-topic
2021-11-15T21:17:17.992Z ff2691cc-a7d0-40f2-a956-277bxxxx821d INFO END
END RequestId: ff2691cc-a7d0-40f2-a956-277bxxxx821d
REPORT RequestId: ff2691cc-a7d0-40f2-a956-277bxxxx821d Init Duration: 0.19 ms Duration: 261.33 ms Billed Duration: 300 ms Memory Size: 128 MB Max Memory Used: 128 MB
In method SNS.publish, you are using callback which is asynchronous in nature and there is a possibility of successful lambda execution before callback is even called. SNS takes a bit of time for execution. you need to use async/ await in this case. AWS APIs support promises.
Here is an example:
const AWS = require('aws-sdk');
exports.lambdaHandler = async (event, context) => {
console.log("START v5");
const SNSarn = process.env.SNS;
console.log(SNSarn);
const snsParams={
Message: "test",
TopicArn: SNSarn
};
const SNS = new AWS.SNS();
try {
const data = await SNS.publish(snsParams).toPromise();
console.log('Sent Message');
context.done(null, 'Done');
} catch (error) {
console.log('We are in the callback!');
context.done(err, 'We have errors');
}
console.log('END');
};

Unable to publish to SNS Topic, getting MessageId as undefined

I have a pretty basic code snippet to test publishing of messages to SNS from Node Lambda:
exports.handler = async () => {
const AWS = require('aws-sdk');
AWS.config.update({region: 'us-east-2'});
let result;
try {
result = await new AWS.SNS({apiVersion: '2010-03-31'}).publish({
TopicArn: 'arn:aws:sns:us-east-2:99999999999:MyTopic',
Message: 'Body of Message 1',
Subject: 'Message 1'
});
} catch (err) {
console.error('xxxxxxxx', err, err.stack);
throw err;
}
console.info('>>>>>> ' + result.MessageId);
}
However, all I repeatedly get in the logs is >>>>>> undefined, and of course, the messages are not being published (because the queue subscribed to this is always empty). I can confirm that the Lambda function has the relevant permissions. What am I doing wrong?
You are not converting publish to a promise. This means that result = await will not work as expected.
Read my old answer for more understanding: How to use Async and Await with AWS SDK Javascript
TLDR;
result = await new AWS.SNS({apiVersion: '2010-03-31'}).publish({
TopicArn: 'arn:aws:sns:us-east-2:99999999999:MyTopic',
Message: 'Body of Message 1',
Subject: 'Message 1'
}).promise(); // !!!

AWS SES create template with lambda function always return null

so on my first time learning AWS stuff (it is a beast), I'm trying to create e-mail templates, I have this lambda function:
// Load the AWS SDK for Node.js
var AWS = require('aws-sdk');
// Set the region
AWS.config.update({ region: "us-east-1" });
exports.handler = async (event, context, callback) => {
// Create createTemplate params
var params = {
Template: {
TemplateName: "notification" /* required */,
HtmlPart: "HTML_CONTENT",
SubjectPart: "SUBJECT_LINE",
TextPart: "sending emails with aws lambda"
}
};
// Create the promise and SES service object
const templatePromise = new AWS.SES({ apiVersion: "2010-12-01" })
.createTemplate(params)
.promise();
// Handle promise's fulfilled/rejected states
templatePromise
.then((data) => {
console.log(data);
callback(null, JSON.stringify(data) );
// also tried callback(null, data);
}, (err) => {
console.error(err, err.stack);
callback(JSON.stringify(err) );
});
as far as I am understanding, this function should return me a template? an object, anything? when I use the lambda test functionality I always got null in the request response
does anyone know what I am doing wrong here?
edit: and It is not creating the e-mail template, I check the SES Panel - email templates and it is empty
edit2: if I try to return a string eg: callback(null, "some success message"); it does return the string, so my guess is something wrong with the SES, but this function is exactly what we have in the AWS docs, so I assume it should just work..
Try not to resolve the Promise and change your code to just returning it as-is:
return await templatePromise;
which should present you some more detail of what is really going wrong in your code - it might be some hidden access issue - so you might need to adjust the role your lambda function is using. createTemplate on the other side should not return much in case of successful execution but just create the template.
Also try to follow the following try/catch pattern when using async (as described here in more detail: https://aws.amazon.com/de/blogs/compute/node-js-8-10-runtime-now-available-in-aws-lambda/)
exports.handler = async (event) => {
try {
data = await lambda.getAccountSettings().promise();
}
catch (err) {
console.log(err);
return err;
}
return data;
};

Lambda Invocation error with callback called: metrics show no errors

I have created a Lambda function in AWS that export logs from Cloudfront to Elasticsearch.
From the AWS console, I still have a warining in front of Invocation error, though the metrics show there is none for more than 24hours.
A typical workflow of logs looks like
START RequestId: 302f0b95-7856-11e8-9486-55b3f10e7d4e Version: $LATEST
Request complete
END RequestId: 302f0b95-7856-11e8-9486-55b3f10e7d4e
REPORT RequestId: 302f0b95-7856-11e8-9486-55b3f10e7d4e Duration: 794.93 ms Billed Duration: 800 ms Memory Size: 128 MB Max Memory Used: 52 MB
There is no error in the logs, and the only thing I guess could trigger this invocation error is that sometimes two request starts at the same time
09:01:47
START RequestId: 63cd00e1-7856-11e8-8f96-1f900def8e65 Version: $LATEST
09:01:47
START RequestId: 63e1e7f3-7856-11e8-97e6-3792244f6ab0 Version: $LATEST
Except from this, I don't understand where this error comes from.
Do I miss something? Or do I have to wait more than 24hours before the satus change? May be there is a way to pinpoint the error with AWS console/API that I did not find about?
Would be happy to hear what you think about this.
Edit: In case you'd like to take a look at the code itself.
var aws = require('aws-sdk');
var zlib = require('zlib');
var async = require('async');
const CloudFrontParser = require('cloudfront-log-parser');
var elasticsearch = require('elasticsearch');
var s3 = new aws.S3();
var client = new elasticsearch.Client({
host: process.env.ES_HOST,
log: 'trace',
keepAlive: false
});
exports.handler = function(event, context, callback) {
var srcBucket = event.Records[0].s3.bucket.name;
var srcKey = event.Records[0].s3.object.key;
async.waterfall([
function fetchLogFromS3(next){
console.log('Fetching compressed log from S3...');
s3.getObject({
Bucket: srcBucket,
Key: srcKey
},
next);
},
function uncompressLog(response, next){
console.log("Uncompressing log...");
zlib.gunzip(response.Body, next);
},
function publishNotifications(jsonBuffer, next) {
console.log('Filtering log...');
var json = jsonBuffer.toString();
var records;
CloudFrontParser.parse(json, { format: 'web' }, function (err, accesses) {
if(err){
console.log(err);
} else {
records = accesses;
}
});
var bulk = [];
records.forEach(function(record) {
bulk.push({"index": {}})
bulk.push(record);
});
client.bulk({
index: process.env.ES_INDEXPREFIX,
type: 'log',
body: bulk
}, function(err, resp, status) {
if(err) {
console.log('Error: ', err);
}
console.log(resp);
next();
});
console.log('CloudFront parsed:', records);
}
], function (err) {
if (err) {
console.error('Failed to send data: ', err);
} else {
console.log('Successfully send data.');
}
callback(null, 'success');
});
};
You need to explicitly return information back to the caller.
Here's the related documentation:
The Node.js runtimes v6.10 and v8.10 support the optional callback
parameter. You can use it to explicitly return information back to the
caller. The general syntax is:
callback(Error error, Object result); Where:
error – is an optional parameter that you can use to provide results
of the failed Lambda function execution. When a Lambda function
succeeds, you can pass null as the first parameter.
result – is an optional parameter that you can use to provide the
result of a successful function execution. The result provided must be
JSON.stringify compatible. If an error is provided, this parameter is
ignored.
If you don't use callback in your code, AWS Lambda will call it
implicitly and the return value is null.
When the callback is called (explicitly or implicitly), AWS Lambda
continues the Lambda function invocation until the event loop is
empty.
The following are example callbacks:
callback(); // Indicates success but no information returned to the caller.
callback(null); // Indicates success but no informatio returned to the caller.
callback(null, "success"); // Indicates success with information returned to the caller.
callback(error); // Indicates error with error information returned to the caller
https://docs.aws.amazon.com/lambda/latest/dg/nodejs-prog-model-handler.html

TypeError: lambda.invoke is not a function

I am trying to call an aws lambda function within another lambda function. I tried a very simple code snippet. However, every time I am receiving "TypeError: lambda.invoke is not a function".
Here is my code:
exports.handler = function(event, context) {
var AWS = require('aws-sdk');
AWS.config.apiVersions = {
lambda: '2015-03-31',
// other service API versions
};
var lambda = new AWS.Lambda();
var params = {
FunctionName: "node-sendsms",
InvocationType: "Event",
LogType: "Tail",
Payload: null
};
lambda.invoke(params, function(err, data) {
if (err) console.log(err, err.stack); // an error occurred
else console.log(data); // successful response
});
};
I referred to the documentation here for invoke function: http://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/Lambda.html#invoke-property
and followed same code. I tried changing api version but that did not help. I also tried looking out for any solution online as well as on SO; at least information I got is that it can be an issue of variable scoping for AWS variable. But, as it can be seen in code - it does not seems like that.
Any experts on this error? I am working on node.js 6.10. Here is error detail:
Response:
{
"errorMessage": "RequestId: 849581c1-d669-11e7-ad15-6f5e52f0e184 Process exited before completing request"
}
Request ID:
"849581c1-d669-11e7-ad15-6f5e52f0e184"
Function Logs:
START RequestId: 849581c1-d669-11e7-ad15-6f5e52f0e184 Version: $LATEST
2017-12-01T07:30:35.785Z 849581c1-d669-11e7-ad15-6f5e52f0e184 TypeError: lambda.invoke is not a function
at exports.handler (/var/task/index.js:22:9)
END RequestId: 849581c1-d669-11e7-ad15-6f5e52f0e184
REPORT RequestId: 849581c1-d669-11e7-ad15-6f5e52f0e184 Duration: 1385.62 ms Billed Duration: 1400 ms Memory Size: 128 MB Max Memory Used: 24 MB
RequestId: 849581c1-d669-11e7-ad15-6f5e52f0e184 Process exited before completing request
install the latest version of aws sdk or mention like
exports.handler = (event, context, callback) => {
var AWS = require('aws-sdk');
AWS.config.apiVersions = {
lambda: '2015-03-31' ///ignore if latest version
};
var lambda = new AWS.Lambda();
refer https://github.com/aws/aws-sdk-js/issues/1823 for more details

Resources