I have a very large multi section script with a LOT of loops and some recursion in it. When I run it on a Very Large dataset, the script will simply stop running. It stops with a 0 exit code. It VERY clearly does not actually finish running...it just...stops.
asyncLib.waterfall([
getPronghornToken,
saveSchedulers,
saveServices,
populateServRefs,
saveServiceGroups,
saveNetworks,
populateNetRefs, //never actually gets out of this function. Just exits with code 0
saveNetworkGroups,
saveRuleGroups,
fetchRuleGroupIds,
populateRules,
saveRules,
getPolicyId,
linkRuleGroup
], function (err, result) {
if (err){
console.error("Something bad happened. Please try again");
process.exit(1);
}
console.log("done");
});
What I'm looking for: Why would a script just stop mid loop and exit with a 0 code?
Note: Alternate code.
getPronghornToken((err, token) => {
if(err) {
console.log("Error occured getPronghornToken");
throw err;
}
saveSchedulers(token, (err, token) => {
if(err) {
console.log("Error occured saveSchedulers");
throw err;
}
saveServices(token, (err, token) => {
if(err) {
console.log("Error occured saveServices");
throw err;
}
populateServRefs(token, (err, token) => {
if(err) {
console.log("Error occured populateServRefs");
throw err;
}
saveServiceGroups(token, (err, token) => {
if(err) {
console.log("Error occured saveServiceGroups");
throw err;
}
saveNetworks(token, (err, token) => {
if(err) {
console.log("Error occured saveNetworks");
throw err;
}
populateNetRefs(token, (err, token) => {
if(err) {
console.log("Error occured populateNetRefs");
throw err;
}
saveNetworkGroups(token, (err, token) => {
if(err) {
console.log("Error occured saveNetworkGroups");
throw err;
}
saveRuleGroups(token, (err, token) => {
if(err) {
console.log("Error occured saveRuleGroups");
throw err;
}
fetchRuleGroupIds(token, (err, token) => {
if(err) {
console.log("Error occured fetchRuleGroupIds");
throw err;
}
populateRules(token, (err, token) => {
if(err) {
console.log("Error occured populateRules");
throw err;
}
saveRules(token, (err, token) => {
if(err) {
console.log("Error occured saveRules");
throw err;
}
getPolicyId(token, (err, token) => {
if(err) {
console.log("Error occured getPolicyId");
throw err;
}
linkRuleGroup(token, (err, token) => {
if(err) {
console.log("Error occured linkRuleGroup");
throw err;
}
console.log("Successfully installed all files");
});
});
});
});
});
});
});
});
});
});
});
});
});
});
No errors thrown. Does NOT print out the innermost message. Callback pattern verified.
Last Function running looks like this:
async function populateNetRefs(token, callback) {
//let newNetRefs = [];
for(let index = 0; index < networkGroups.length; index++) {
if (index >= networkGroups.length) {
console.log("Net Refs Finished")
return callback(null, token);
}
let networkGroup = networkGroups[index];
try {
console.log(`fetching network number: ${index+1} / ${networkGroups.length}`);
let newNetRefs = await fetchNetId(token, networkGroup._netRefs);
networkGroup._netRefs = newNetRefs;
} catch (err) {
console.log(`An error occurrent fetching the network id for index ${index+1} / ${networkGroups.length}: ${err}`);
}
}
}
The Inner Function:
function fetchNetId(token, _netRefs) {
let fetchFinished = 0;
let newNetRefs = [];
let errCount = 1;
console.log("ZZ Fetchid Start ZZ");
return new Promise((resolve, reject) => {
_netRefs.forEach(function(_netRef) {
let options = {
//Required to be hidden
};
let req = https.request(options, (res) => {
let reply = [];
res.setEncoding('utf8');
res.on('data', (chunk) => {
console.log("YY GET DATA CHUNK YY");
reply.push(chunk);
});
res.on('end', () => {
fetchFinished++;
console.log("Reply is : " + reply.join());
//There is some logic in this spot. Not for you.
console.log("fetchFinished is: " + fetchFinished + ", size is: " + _netRefs.length);
if (fetchFinished === _netRefs.length) {
resolve(newNetRefs);
}
});
});
req.on('error', (e) => {
console.error(`problem with request ${errCount++}: ${e.message}`);
//reject(e);
});
let body = JSON.stringify({
"options" : {
"start": 0,
"limit": 5,
"sort": {
},
"filter": {
"name":{"$eq":_netRef}
}
}
});
console.log("XX Sending Request XX");
req.write(body);
req.end();
});
});
}
BEHAVIOR UPDATE - More Console Logs
Here's the end of the console log:
fetching network number: 49 / 711
ZZ Fetchid Start ZZ
XX Sending Request XX
XX Sending Request XX
YY GET DATA CHUNK YY
Reply is : {hidden from you}
TroubleShootingDias: some guid
fetchFinished is: 1, size is: 2
YY GET DATA CHUNK YY
Reply is : {hidden from you}
TroubleShootingDias: some guid
fetchFinished is: 2, size is: 2
fetch success
fetching network number: 50 / 711
ZZ Fetchid Start ZZ
[vagrant#vag-host1 space-parser]$
I highly recommend you look at async.waterfall to help structure code like this as it can be a mare to debug and read. A lot to grasp in your code above, but it could be helpful to wrap the following in a try catch. While you are handling req errors - those are only request errors and there may be something else including possible malformed url etc that will throw and you don't have the promise returning in this instance.
try {
let req = https.request(options, (res) => {
let reply = [];
res.setEncoding('utf8');
res.on('data', (chunk) => {
console.log("YY GET DATA CHUNK YY");
reply.push(chunk);
});
res.on('end', () => {
fetchFinished++;
console.log("Reply is : " + reply.join());
//There is some logic in this spot. Not for you.
console.log("fetchFinished is: " + fetchFinished + ", size is: " + _netRefs.length);
if (fetchFinished === _netRefs.length) {
resolve(newNetRefs);
}
});
});
req.on('error', (err) => {
console.error(`problem with request ${errCount++}: ${err.message}`);
return reject(err);
});
}
catch(err) {
console.error(`problem with request ${err.message}`);
return reject(err);
}
Actual solution to the problem: If the array is empty, then the promise never resolves. Added an empty check to the very top, before the loop.
function fetchNetId(token, _netRefs) {
let fetchFinished = 0;
let newNetRefs = [];
let errCount = 1;
console.log("ZZ Fetchid Start ZZ");
return new Promise((resolve, reject) => {
if(_netRefs.length === 0) return resolve([]) // <==============
_netRefs.forEach(function(_netRef) {
let options = {
//Required to be hidden
};
let req = https.request(options, (res) => {
let reply = [];
res.setEncoding('utf8');
res.on('data', (chunk) => {
console.log("YY GET DATA CHUNK YY");
reply.push(chunk);
});
//........
Related
I am using node js function i have written the code long before but i need to add async and await in my functions i don know how to proceed with my code structure .
Here is my code structure
app.express.get('/api/member/logout', function (request, response) {
functionBal.logout(request.query.abc).then(function (result) {
if (result) {
response.set('Content-Type', 'application/json');
response.status(200);
response.json(result);
}
}).catch(function (err) {
response.set('Content-Type', 'application/json');
response.status(400);
response.json("Error -- " + err);
});
});
module.exports.log = function (abc) {
return new app.promise(function (resolve, reject) {
functionDal.log(abc).then(function (result) {
if (result)
resolve(result);
else {
reject("Error");
}
}).catch(function (err) {
reject(err);
});
})
};
module.exports.log = function (abc) {
return new app.promise(function (resolve, reject) {
mySqlConnection.connection().then(function (con) {
con.query("UPDATE member SET table1 = 0 WHERE abc = ?", [abc]).then(function (rows, fields) {
resolve('success');
}).catch(function (err) {
reject(err);
});
}).catch(function (err) {
reject(err);
});
});
}
Please help in adding async await in this coding structure
Give this is try.
app.express.get('/api/member/logout', async function (request, response) {
try {
let data = await functionBal.logout(request.query.abc)
response.set('Content-Type', 'application/json');
response.status(200);
response.json(result);
} catch (error) {
response.set('Content-Type', 'application/json');
response.status(400);
response.json("Error -- " + err);
}
});
module.exports.log = async function (abc) {
try {
return await functionDal.log(abc)
} catch (error) {
throw error
}
};
module.exports.log = async function (abc) {
try {
const con = await mySqlConnection.connection()
await con.query("UPDATE member SET table1 = 0 WHERE abc = ?", [abc])
return 'success'
} catch (error) {
throw error
}
}
Make sure, you have Node.js 8+.
I am trying to call a function inside my post API. I have multiple queries and want to wait for the function to complete in order to execute the next queries. I am having an issue here. The function isn't completing the execution and the rest of the API gets executed as expected. How can I wait for the function to complete its execution? I have searched but couldn't find something convenient and related to my code.
Here's the code:
Node.js
function verifyEmail(mailToUpper)
{
var emailResult;
db2.open(mydbConnection, (err, conn) => {
if(!err)
{
console.log("Connected Successfully");
}
else
{
console.log("Error occurred while connecting to the database " + err.message);
}
conn.query(checkEmailQuery, [mailToUpper], (err, results) => {
if(!err)
{
if(results.length > 0)
{
// res.write("Email already exists");
emailResult = 0;
}
else
{
emailResult = 1;
}
}
conn.close((err) => {
if(!err)
{
console.log("Connection closed with the database");
}
else
{
console.log("Error occurred while trying to close the connection with the database " +
err.message);
}
})
})
})
return emailResult;
}
router.post('/api/postData', (req, res) => {
//some stuff
var waitingForResult;
setTimeout(() => {
waitingForResult = verifyEmail(mailToUpper);
}, 2000)
console.log(waitingForResult); //throwing an error of undefined
if(waitingForResult === 1) //not executing this
{
//my other queries
}
else //always executes this
{
res.send("Email already exists");
}
});
function verifyEmail(mailToUpper) {
return new Promise((resolve, reject) => {
db2.open(mydbConnection, (err, conn) => {
if (!err) {
console.log("Connected Successfully");
} else {
console.log("Error occurred while connecting to the database " + err.message);
}
conn.query(checkEmailQuery, [mailToUpper], (err, results) => {
if (!err) {
if (results.length > 0) {
// res.write("Email already exists");
resolve(0);
} else {
resolve(1);
}
}
conn.close((err) => {
if (!err) {
console.log("Connection closed with the database");
} else {
console.log("Error occurred while trying to close the connection with the database " +
err.message);
}
})
})
})
})
}
router.post('/api/postData', async (req, res) => {
const waitingForResult = await verifyEmail( mailToUpper );
if( waitingForResult === 1 ){
//my other queries
} else {
res.send("Email already exists");
}
});
function unzipCode() {
console.log('Unzipping contents...');
return new Promise((resolve, reject) => {
const files = [];
unzip.open(filePath, { autoclose: false, lazyEntries: true }, (err, zipfile) => {
if (err) reject;
zipfile.readEntry();
zipfile.on('entry', (entry) => {
if (!sourceDirectoryRegEx.test(entry.fileName)) {
console.log(" [X] Skipping: " + entry.fileName);
zipfile.readEntry();
}
else {
console.log(" [+] Unzipping: " + entry.fileName);
if (/\/$/.test(entry.fileName)) {
// directory file names end with '/'
mkdirp(path.join(cwd, entry.fileName), (err) => {
if (err) reject;
zipfile.readEntry();
});
}
else {
zipfile.openReadStream(entry, (err, readStream) => {
if (err) reject;
// ensure parent directory exists
mkdirp(path.join(cwd, path.dirname(entry.fileName)), (err) => {
if (err) reject;
let stream = fs.createWriteStream(path.join(cwd, entry.fileName));
readStream.pipe(stream, { end: false });
// console.log(readStream.pipe);
readStream.on('end', () => {
console.log('After write', entry.fileName);
// add file details to files array
files.push({
key: entry.fileName,
body: stream,
});
zipfile.readEntry();
readStream.unpipe(stream);
stream.end();
});
});
});
}
}
});
zipfile.once('end', () => {
zipfile.close();
resolve(files);
});
});
});
}
I am trying to unzip some files in aws-lambda console using the function. The enviornment I've chosen is nodejs 12.x. It was running with nodejs 8.10.
The exact error I'm encountering is Cannot pipe, not readable.
How to solve it?
I am trying to call method get_radar_life_cycle from app.get("/api/radar_cloning and it throws the error shown below,
error is coming from line return done(null,documents) how do I return documents back to my API call?
METHODS:-
let get_cloned_radars = function(documents, done) {
let complete_radar_list=[]
for (let i = 0; i < documents.length; i++) {
complete_radar_list.push(documents[i]['orgRadar']);
for (let j = 0; j < documents[i]['clonedRadarsdetailslist'].length; j++) {
complete_radar_list.push(documents[i]['clonedRadarsdetailslist'][j]['clonedRadar']);
}
}
data = complete_radar_list
return done(null, data)
}
let get_radar_life_cycle = function(data,done) {
console.log("data after get_radar_life_cycle")
console.log(data)
Radar_life_cycle.find({orgRadar: {$in:data}})
.then(documents => {
console.log(documents) --> shows correct data
});
return done(null,documents) --> Error is coming from this line
};
API call:
app.get("/api/radar_cloning", (req, res, next) => {
Radar_cloning.find({orgRadar: {$in:req.query.params.split(',')}})
.then(documents => {
get_cloned_radars(documents, function(err,data) {
if (err) {
res.json(err);
if (data!=null){
console.log(data)
}//end for data
}//end of (Err)
});//get_cloned_radars
get_radar_life_cycle(data, function(err,radar_life_cycle_data) {
if (err) {
res.json(err);
console.log(radar_life_cycle_data)
}//end for radar_life_cycle_data
}//end of (Err)
});//end of get_radar_life_cycle
});
});
ERROR:-
(node:10065) UnhandledPromiseRejectionWarning: ReferenceError: documents is not defined
You are trying to access documents outside of its scope, the scope being everything between the { and }. So you cannot access it below the .then(() => {}) scope.
Luckily you are are providing a callback function called done(err, radar_life_cycle_data), which you can use anywhere in the scope of the get_radar_life_cycle(documents, done) function. Even the scopes inside of its scope. When you are calling the done function, what you are basically doing is calling this function (well it has some syntax errors, so I cleaned it up)
function(err,radar_life_cycle_data) {
if (err) {
res.json(err);
console.log(radar_life_cycle_data)
}
}//end for radar_life_cycle_data
which then gets executed
So the solution:
Move your done in your .then(() => {}) scope like this:
let get_radar_life_cycle = function(data,done) {
console.log("data after get_radar_life_cycle")
console.log(data)
Radar_life_cycle.find({orgRadar: {$in:data}})
.then(documents => {
console.log(documents) // --> shows correct data
done(null,documents) // --> No error coming from this line
});
};
Same goes for the data it is not in the scope of the get_cloned_radars
app.get("/api/radar_cloning", (req, res, next) => {
Radar_cloning.find({orgRadar: {$in:req.query.params.split(',')}})
.then(documents => {
get_cloned_radars(documents, function(err,data) {
if (err) {
res.json(err);
if (data!=null) {
console.log(data)
get_radar_life_cycle(data, function(err,radar_life_cycle_data) {
if (err) {
res.json(err);
console.log(radar_life_cycle_data)
} //end of (Err)
}); //end of get_radar_life_cycle
} //end for data
} //end of (Err)
}); //get_cloned_radars
});
But since your code is unreadable, here is a cleaned up version:
app.get("/api/radar_cloning", (req, res, next) => {
const radar_life_cycle_cb = function (err, data) {
if (err) {
res.json(err);
return;
}
console.log(data);
}
const cloned_radar_cb = function (err, data) {
if (err) {
res.json(err);
return;
}
if (data != null) {
get_radar_life_cycle(data, radar_life_cycle_cb);
}
};
Radar_cloning.find({orgRadar: {$in:req.query.params.split(',')}})
.then(documents => get_cloned_radars(documents, cloned_radar_cb));
}
Hi I have a problem running a loop and getting the return data using Promises.
I have a getStudentMarks method for getting students marks from the database in subject wise.
getStudentMarks: function(studentId, studentStandard) {
console.log("getStudentMarks invoked...");
return new Promise(function(resolve, reject) {
r.table('student_subjects').filter({
"studentId": studentId,
"studentStandard": studentStandard
}).pluck("subjectId", "subjectName").run(connection, function(err, cursor) {
if (err) {
throw err;
reject(err);
} else {
cursor.toArray(function(err, result) {
if (err) {
throw err
} else {
console.log(result.length);
if (result.length > 0) {
studentSubjectArray = result;
var studentMarksSubjectWiseArray = [];
studentSubjectArray.forEach(function(elementPhoto) {
r.table('student_marks').filter({
"studentId": studentId,
"subjectId": studentSubjectArray.subjectId
}).run(connection, function(err, cursor) {
if (err) {
throw err;
reject(err);
} else {
cursor.toArray(function(err, result_marks) {
var studnetMarksDataObject = {
subjectId: studentSubjectArray.subjectId,
subjectName: studentSubjectArray.subjectName,
marks: result.marks
};
studentMarksSubjectWiseArray.push(studnetMarksDataObject);
});
}
});
});
resolve(studentMarksSubjectWiseArray);
}
}
});
}
});
});
}
I'm invoking the method by,
app.post('/getStudentMarks', function(req, reqs) {
ubm.getStudentMarks(req.body.studentId, req.body.studentStandard)
.then((data) => {
console.log('return data: ' + data);
})
.catch((err) => {
console.log(err);
});
});
When I run the code its working absolutely fine there is no error. I get all the student marks object in the studentMarksSubjectWiseArray array. But the problem is even before the studentSubjectArray loops gets completed, the resolve is getting executed and I'm getting a blank array as return. How do I solve the problem. I understand that I'm not doing the Promises right. I'm new to Promises so I'm not being able to figure out the right way.
That happens because inside your studentSubjectArray.forEach statement you perform set of asynchronous operations r.table(...).filter(...).run() and you push their result into the array. However, those actions finish after you perform the resolve(), so the studentMarksSubjectWiseArray is still empty. In this case you would have to use Promise.all() method.
let promisesArray = [];
studentSubjectArray.forEach((elementPhoto) => {
let singlePromise = new Promise((resolve, reject) => {
// here perform asynchronous operation and do the resolve with single result like r.table(...).filter(...).run()
// in the end you would perform resolve(studentMarksDataObject)
r.table('student_marks').filter({
"studentId": studentId,
"subjectId": studentSubjectArray.subjectId
}).run(connection, function(err, cursor) {
if (err) {
throw err;
reject(err);
} else {
cursor.toArray(function(err, result_marks) {
var studnetMarksDataObject = {
subjectId: studentSubjectArray.subjectId,
subjectName: studentSubjectArray.subjectName,
marks: result.marks
};
resolve(studnetMarksDataObject);
});
}
});
});
promisesArray.push(singlePromise)
});
Promise.all(promisesArray).then((result) => {
// here the result would be an array of results from previously performed set of asynchronous operations
});