I put my code into different modules:
.....
var util = require('util');
var s3 = new AWS.S3();
exports.perform_flatten = function(event, context) {
.......
CONTEXT = context;
s3_helper.get_object(SRC_BUCKET, SRC_KEY, this.flatten);
};
this.flatten is a callback to a module in the same file
exports.flatten = function(data){
.......
s3.putObject({Bucket: dst_bucket, Key: dst_key, Body: buffer}, function(err, data) {
if (err){
console.log(err, err.stack); // an error occurred
}else{
console.log(data); // successful response
CONTEXT.done();
}
});
}
The code runs perfectly until it comes to this line CONTEXT.done();.
Then I get the error: undefined is not a function
I do not understand why? Especially because I believe I declared CONTEXT as global right?
I have to call context.done() in order to execute a Lambda function on Amazon. http://docs.aws.amazon.com/lambda/latest/dg/programming-model.html THANKS
Related
I'm new to Node.js, Javascript and callbacks. I have a pretty simple program I'm trying to write and I can't get the callbacks to work.
Here's the relevant code:
var keysfetched = false;
var urlsfetched = false;
function setKeysfetched(){
keysfetched = true;
}
function setUrlsfetched(){
urlsfetched = true;
}
//get list of all media in bucket
getKeys(setKeysfetched);
//get a list of all media urls in DB
getUrls(setUrlsfetched);
//check for media in the bucket which is not used
checkKeys();
function getKeys(callback) {
S3.listObjectsV2(params, function(err, data) {
if (err) console.log(err, err.stack); // an error occurred
else{
var contents = data.Contents;
contents.forEach(function (content) {
allKeys.push(content.Key);
});
if (data.IsTruncated) {
params.ContinuationToken = data.NextContinuationToken;
//console.log("get further list...");
getKeys();
}
else{
console.log("end of loop...");
}
}
});
callback()
}
When I run this I get an error : Error [TypeError]: callback is not a function
If I comment out all of the code inside getKeys(), I don't get the error.
This runs just fine:
function getKeys(callback) {
//Hard work here
callback()
}
What am I doing wrong?
You are passing callback and calling it at the bottom of getKeys but inside you are not passing any callback
if (data.IsTruncated) {
params.ContinuationToken = data.NextContinuationToken;
//console.log("get further list...");
getKeys();
}
So it's trying to call undefined which is not a function.
I am a newbie in Node JS and trying to get my head around functional programming.
I have the following code in a file called findinfo.js and I'm trying to pass the result to the main server.js:
const fs = require('fs');
const values = ["yes", "no", "?", "unknown", "partial"];
var cInfo = [];
function getFile (cb) {
fs.readFile('./scripts/blahblah.json', 'utf-8', function (err, jfile) {
if (err) {
throw new Error (err);
}
console.log("Function is executing...")
JSON.parse(jfile);
console.log('Parsing file done');
cb(jfile);
});
}
Then I'm trying to call this function from server.js,
var findinfo = require('./findinfo');
console.log(getFile());
which as expected crashes the program.
So what changes should I make in order to make it work?
You need to export getFile so it can be imported using require.
const fs = require('fs');
const values = ["yes", "no", "?", "unknown", "partial"];
var cInfo = [];
function getFile (cb) {
fs.readFile('./scripts/blahblah.json', 'utf-8', function (err, jfile) {
if (err) {
// throw new Error (err); // don't throw inside async callback
return cb(err);
}
console.log("Function is executing...")
JSON.parse(jfile);
console.log('Parsing file done');
cb(null, jfile);
});
}
module.exports = getFile;
server.js
var getFile = require('./findinfo');
getFile(function(err, file) {
console.log(err, file);
});
since getFile is an asynchronous function, you have to wait until it finishes, when cb is called, to console.log the result.
And using throw in a asynchronous callback is not recommended, since it will crash the server, it's recommended to pass the error to the callback.
You should take a look at this question, so you learn more about how to handle asynchronous code.
How do I return the response from an asynchronous call?
I want to merge data from two tables and then send the result as the response.
I'm new to nodejs and lambda and I'm unable to figure out how I can merge json data from both scan calls and send it as the response.
If I uncomment the callback then response for only one table is sent.
My code is below, can someone please help in completing it
'use strict';
const AWS = require("aws-sdk");
const dynamodb = new AWS.DynamoDB();
const docClient = new AWS.DynamoDB.DocumentClient();
exports.handler = function(event, ctx, callback) {
var params= {
TableName:'x',
FilterExpression:'SessionId = :SessionId',
ExpressionAttributeValues:{ ":SessionId" : 'ca47a131'},
};
var params1= {
TableName:'y',
FilterExpression:'sessionid = :SessionId',
ExpressionAttributeValues:{ ":SessionId" : 'ca47a131'},
};
docClient.scan(params, onScan);
docClient.scan(params1, onScan1);
function onScan(err, data){
if(err){
callback(err, null);
}else{
//callback(null, data);
}
}
function onScan1(err, data){
if(err){
callback(err, null);
}else{
//callback(null, data);
}
}
}
You can use the following modification to the code so that you can send the response in a single callback.
'use strict';
const AWS = require("aws-sdk");
const dynamodb = new AWS.DynamoDB();
const docClient = new AWS.DynamoDB.DocumentClient();
exports.handler = function(event, ctx, callback) {
var params= {
TableName:'x',
FilterExpression:'SessionId = :SessionId',
ExpressionAttributeValues:{ ":SessionId" : 'ca47a131'},
};
var params1= {
TableName:'y',
FilterExpression:'sessionid = :SessionId',
ExpressionAttributeValues:{ ":SessionId" : 'ca47a131'},
};
docClient.scan(params, onScan);
docClient.scan(params1, onScan1);
var firstResultData = false;
function runAfterBothCallbacks(data){
if(!firstResultData){
firstResultData = data;
}else{
// Combine firstResultData with data and return in the callback
callback(null,{ dataX: firstResultData, dataY: data });
// Note: The order of scan and scan1 result coming cannot be guaranteed so, dataX can be the results of scan or scan1. If you can identify the result based on the scan, either pass it as another parameter to the runAfterBothCallbacks method or identify the scan based on data result (If possible).
}
}
function onScan(err, data){
if(err){
callback(err, null);
}else{
runAfterBothCallbacks(data);
}
}
function onScan1(err, data){
if(err){
callback(err, null);
}else{
runAfterBothCallbacks(data);
}
}
}
Welcome to JavaScript asynchronous callbacks (aka callback hell).
Fortunately, the AWS SDK supports promises so you can use Promise.all() to wait for multiple promises to be resolved. When that happens, merge the JSON results and return the merged result via the Lambda function's callback() method.
I have a Lambda function that imports a node package with common functions. Lambda 1 puts messages into SQS, Lambda 2 does error logging. One of the shared functions invokes Lambda 2, but there's an error on that second invocation.
Lambda 1:
exports.handler = function (event, context) {
var pnmacCommon = require('./pnmacCommon.js'); //loading node package
try {
// this part omitted for space
var aws = require('aws-sdk');
var sqs = new aws.SQS({ region : 'us-west-2' });
var params = {
MessageBody: JSON.stringify(event),
QueueUrl: '[url]'
};
sqs.sendMessage(params, function(err,data){
if(err) {
console.log('error:',"FAIL Send Message: " + err);
context.done(err, "ERROR Put SQS"); // ERROR with message
pnmacCommon.SvtLogErrorToElmah(application, "FAIL Send Message: " + err, context);
}else{
console.log('Message Sent:', queueUrl);
console.log('data:',data.MessageId);
context.done(null,''); // SUCCESS
}
}
});
}
catch (error) {
pnmacCommon.SvtLogErrorToElmah(application, 'SVTMessageBus_Client' + error, context);
context.done(error, "ERROR put SQS");
}
pnmacCommon.js:
var SvtLogErrorToElmah = function (application, error, context) {
console.log("SvtLogErrorToElmah=" + JSON.stringify(error, null, 2));
// this part omitted for space
var aws = require('aws-sdk');
var lambda = new aws.Lambda({region: 'us-west-2' });
lambda.invoke({
FunctionName: "SVTExceptionLogger",
Payload: JSON.stringify(message, null, 2)
}, function (error2, data) {
if (error2) {
context.fail(error2);
} else {
context.fail(error);
});
context.done(null, message);
}
module.exports.SvtLogErrorToElmah = SvtLogErrorToElmah;
Looking in Cloudwatch, I can see that the SvtLogErrorToElmah function gets called, but it fails when it tries to invoke the second Lambda. The error message is TypeError: lambda.invoke is not a function.
Any ideas? Thank you in advance.
It turns out this was an issue with variable scoping. In the shared function, we reuse the variable name aws. Once I changed this to a different name, the problem went away.
I just got the same error that you had, and for me the update of the aws-sdk version resolved the issue.
UPDATED the package.json [aws-sdk version]
old (with 'TypeError: lambda.invoke is not a function')
"dependencies": {
"aws-sdk": "^2.1.17"
}
to (fixed the error)
"dependencies": {
"aws-sdk": "^2.18.0"
}
I am just two days into node.js. I am attempting to write my own module, which uses fs (filesystem) api. The code is as below:
var fs=require('fs');
var path=require('path');
// pkg file name constant
const PKG_FILE = 'pkg.json';
module.exports = function(srcDir, targetDir, callback) {
console.log('checking dir: ', srcDir, '...');
fs.readdir(srcDir, function(err, files) {
// early return, in case of error.
if (err) return callback(err);
// look for pkg.json file and if found, iterate through
// the list of components
var pkgFile = path.join(srcDir, PKG_FILE);
console.log(pkgFile);
var pkg = fs.readFile(pkgFile, function(err, data) {
if (err) return callback(err);
var obj = JSON.parse(data);
for (var attr in obj) {
console.log(attr, " : ", obj[attr]);
}
});
});
}
In the above code, I am trying to return to the caller, via the statement
if (err) return callback(err);
However, when an fs error occurs, I get a different error indicating that callback is undefined. Exact error is below:
rvnath#rv ~/projects/comviva/mbs/node/siteright $ node pkgtest.js riu3
checking dir: riu3 ...
/home/rvnath/projects/comviva/mbs/node/siteright/libs/pkgcreator.js:17
if (err) return callback(err);
^
TypeError: undefined is not a function
at /home/rvnath/projects/comviva/mbs/node/siteright/libs/pkgcreator.js:17:20
at FSReqWrap.oncomplete (fs.js:95:15)
Does this mean that I am not supposed to call "return callback(err) in nested closures?
Thanks to anyone for correcting me.
regards.
EDIT
I am using my module as below.
rvnath#rv ~/projects/comviva/mbs/node/siteright $ cat pkgtest.js
var packager = require('./libs/pkgcreator');
packager(process.argv[2], function(err, files) {
//if (err) {
//console.log("some error occurred", err);
//return;
//}
console.log("files listing...");
files.forEach(function(file) {
console.log(file);
});
});
In case of success, I get the result correctly.
checking dir: /home/rvnath/projects/comviva/mbs/ecp/ecp_6.0 ...
/home/rvnath/projects/comviva/mbs/ecp/ecp_6.0/pkg.json
reading module: smp3
reading module: pushp
reading module: bulkp
reading module: drp
reading module: mop
reading module: ecp_ws
reading module: ecp_admin
but for failure, it says callback undefined.
As expected, you are not passing a callback to the function which you are exporting -- it is indeed undefined. Simply add an anonymous function as third parameter to the function from your module, and the problem should be gone.
packager(process.argv[2], function(err, files) {
// your code
}, function(err) {
// The actual callback
console.log('Sadly, something went wrong: ' + err);
});