Node does not send response after child process exits - node.js

I have the following route:
app.get('/downloadSentinel', function (req,res){
var promObj = {};
var data = req.query.data;
var Name = req.query.name;
namesArray = [];
for(var i =0;i<Name.length;i++){
namesArray.push(Name[i]);
}
promObj['Name'] = namesArray;
console.log(promObj.Name);
requestarray = [];
for (i=0; i<data.length;i++) {
requestarray.push(data[i]);
promObj['requestURLS'] = requestarray;
}
createResultFolder(promObj)
.then(downloadSentinel)
.then(resp => {
console.log("THEN:", resp);
res.send(resp);
}).catch((err) => {
console.log("CATCH:", err)
res.send(err);
})
});
The function downloadSentinel calls a Node child process and looks like this:
function downloadSentinel(promObj){
return new Promise((resolve,reject) =>{
var sys = require('util'),
exec = require('child_process').exec,
child;
var urls = parseArrayForBash(promObj.requestURLS);
var names = parseArrayForBash(promObj.Name);
console.log("executing:", './downloadProducts.sh ' + urls + ' ' + names);
child = exec('bash downloadProducts.sh '+ urls + ' ' + names, [{stdio:'inherit'}]);
child.stderr.pipe(process.stderr);
child.stdout.pipe(process.stdout);
child.on("error", function (error) {
console.log("child error:", error);
reject(promObj)
})
child.on('data', function (data) {
console.log(data.toString());
});
child.on('exit', function (exit) {
console.log("child exit:", exit);
resolve(promObj);
})
}
})
}
The output of downloadSentinel is :
child exit: 0
THEN: { Name:
[ 'S2A_MSIL1C_20180315T041541_N0206_R090_T46QEH_20180315T075531',
'S2A_MSIL1C_20180315T041541_N0206_R090_T46QEK_20180315T075531' ],
requestURLS:
[ 'bb5f4946-ce18-4b50-97ba-7ac9a94d9f1e',
'ec15c5d4-0cc6-44d4-a11f-6c2e9055f2e4' ] }
So I think that everything works as expected. But after the child process has exited with code 0, the response res.send(resp); is not sent to the client and I never get the sucess message.
What am I doing wrong?
P.S.: Sorry for the large amount of code, but I don't know what I made wrong so I provided everything.
EDIT
For the client part I am using this jQuery Ajax Request:
function downloadSentinelData(ID,Name){
var url = encodeURI('/downloadSentinel?');
$.ajax({
type: 'GET',
url: url,
timeout:5000,
dataType:'json',
data: {
data: ID,
name: Name
},
success: function(data,status){
console.log(data);
console.log(status);
alert('Products downloaded. Processing now.');
},
error: function (errorMessage) {
}
});
}
Could there be a mistake?

If you are using express.js, you should do res.end() after the res.send

Related

before fetching data in db response is sent by node js

this is my set notification object
var sentNotificationObj = function (notification, eventid, addedorganizerpropic) {
this.notification = notification;
this.eventid = eventid;
this.addedorganizerpropic = addedorganizerpropic;
}
this is my array which is stored notification obect
var notificationSetArray2 = [];
this is my api of getnotification
router.post('/getnotification', function (req, res) {
console.log('in aside');
var id = req.body.userid;
console.log('pos id' + id);
User.findById({ _id: id }, function (err, result) {
if (err) {
console.log('err get notification');
res.statusCode = 500;
res.json({
success: false,
message: "severe error"
});
} else {
this is code fetchin data in data base
for (var i = 0; i < result.notification.length; i++) {
var addedevent = result.notification[i].addedevent;
var notification = result.notification[i].notification;
console.log('added event' + addedevent);
console.log('added noti' + notification);
User.findById({ _id: result.notification[i].addedorganizer }, function (err, addedorganizer) {
if (err) {
console.log('error get added user pofile pic');
} else {
convert image to base64
var base64str = base64_encode(addedorganizer.profileData.profileurl);
console.log(base64str);
console.log(notification);
console.log(addedevent);
var newsentNotificationObj = new sentNotificationObj(notification, addedevent, base64str);
notificationSetArray2.push(newsentNotificationObj);
console.log('succe get added user profile pic');
}
});
}
this is response
res.statusCode = 200;
res.json({
success: true,
notificationArray: notificationSetArray2
})
console.log(notificationSetArray2);
notificationSetArray2.length = 0;
}
});
});
The most simple solution in here to use async library here.
Node runs code in asynchronous way. So it is natural to send response before fetching any data from your database.
By using async you can execute this in a sequence. So it will be solved.
Use async.series method for solve this. For example
async.series(
[
function(callback){
// fetch your data here using mongo with your loop
//
//
callback(); // this will trigger next step (call this after you finished iterating array)
},
function(callback){
// after above code has been executed
// send response here
callback() // call this to proceed
}
],
function(err){
// handle any error in here
}
)
A good example of how to use asyncjs in node

multiple http get calls nodejs

Thanks for looking into the code.
Here I am fetching some data using feed parser and taking out id's in navcodes array variable and wants to use these Id to make http call.Please find code below.
function processNavCode(){
var mfId = [53];
var preTitle = '';
var navCodes = [];
mfId.forEach(function(id){
var query = "http://portal.xyz.com/Rss.aspx?mf="+id;
feed(query, function(err, feeds) {
if (err) {
throw err;
}
feeds.forEach(function(feed){
var link = feed.link;
var title = feed.title;
var navCode = link.substr(link.length - 6);
if(title.split('-')[0].trim() != preTitle){
preTitle = title;
counter ++;
}
if(parseInt(navCode) != '')
navCodes.push = parseInt(navCode);
});
});
async.eachSeries(navCodes,insertbulkMFValues,function(){
console.log('I am done');
});
// insertbulkMFValues(navCode);
//Directly call insertbulkMFValues function
});
}
I have also tried to call the insertbulkMFValues directly as commented now but due to async nature of nodejs, I am getting the error of either 'Socket hang up' or 'read ECONNRESET'. I checked and used async but not able to work with that also.
var insertbulkMFValues =function(navCode,callback){
var options = {
host: 'www.quandl.com',
path: '/api/v3/datasets/AMFI/'+navCode+'.json?api_key=123456789&start_date=2013-08-30',
method: 'GET',
headers: {
'Content-Type': 'application/json'
}
}
var req1 = https.request(options, function(response) {
var body = '';
response.setEncoding('utf8');
response.on('data', function(chunk) {
body += chunk;
});
response.on('end', function() {
if(typeof body === "string") {
var json = JSON.parse(body);
}
var mfData = json.dataset.data;
var schemeId = json.dataset.dataset_code;
var schemeName = json.dataset.name;
var isinCode = json.dataset.description;
var valueData=[];
for (var k = 0; k < mfData.length; k++) {
var myDate = new Date(mfData[k][0]);
valueData.push({
date:myDate,
NAV:parseFloat(mfData[k][1]).toFixed(2)
});
}
var query = { "navCode": schemeId };
var newData = {
createdDate: Date.now(),
navCode: schemeId,
schemeCode:count,
schemeName:schemeName,
ISINCode:isinCode,
values:valueData
};
MHistory.findOneAndUpdate(query, newData , {upsert:true}, function(err, doc){
if(err)
console.log('Errorr');
else
console.log('Success');
});
});
});
req1.on('error', function(e) {
console.log('problem with request: ' + e.message);
callback(true);
});
req1.end();
}
Thanks in advance..
J
You can directly call insertbulkMFValues for each navCode like:
if(parseInt(navCode) != '') {
insertbulkMFValues(navCode, function () {
console.log('something'}
});
}
Anything that you intend to do must be within the callback of the asynchronous function.
One option for you is to use the waterfall or parallel method of the async library to retrieve all feeds for each id and then invoke
async.eachSeries(navCodesAccumulated,insertbulkMFValues,function(){
console.log('I am done');
});
within the final result callback using the codes obtained.

Loop callback in async.waterfall node js

I want to execute the callback in the else of my each loop. In my console i have the "Found" written but the callback isn't executed ...
async.waterfall([
function readFile(callback){
console.log("Start async");
var params = {Bucket : "MyBucket", Key: "MyKey"};
reads3.getObject(params, function extract(err,data) {
//read a json object
console.log("Start reading");
callback(err,data);
});
},
function(data, callback){
var content = data.Body.toString('utf-8').trim();
var jsonparse = JSON.parse(content);
async.each(config, function(item) {
var currentPath = item.path;
if((key.search(currentPath)) === (-1)) {
console.log("No found !");
} else {
console.log("Found");
callback(jsonparse);
}
});
},
function(jsonparse){
console.log("In the 2nd loop !");
}
]);
can you try this
async.waterfall([
function readFile(callback){
console.log("Start async");
var params = {Bucket : "MyBucket", Key: "MyKey"};
reads3.getObject(params, function extract(err,data) {
//read a json object
console.log("Start reading");
callback(err,data);
});
},
function(data, callback){
var content = data.Body.toString('utf-8').trim();
var jsonparse = JSON.parse(content);
async.each(config, function(item) {
var currentPath = item.path;
if((key.search(currentPath)) === (-1)) {
console.log("No found !");
} else {
console.log("Found");
callback(null,jsonparse);
}
});
},
function(jsonparse,callback){
console.log("In the 2nd loop !");
callback(null,'result');
}
],function(err,data){
//your data is result
//......Your function script
});

How to return the callback in a variable in node.js with npm synchronize

I'm using nodejs and I want to avoid multiple nested callbacks. How can I use synchonize to do that ?
More precisely how can I return the pubkeysObj from the callback of the request in a variable and use it in the rest of the script ?
var sync = require('synchronize');
var fiber = sync.fiber;
var await = sync.await;
var defer = sync.defer;
try {
fiber(function() {
console.log('before findKeyPair');
var pubkeysObj2 = await( findKeyPair( defer() ) );
console.log('after findKeyPair pubkeysObj2: ' + pubkeysObj2);
console.log('before makeKeyPairs');
var pubkeyArray2 = await( makeKeyPairs( pubkeysObj2, defer() ) );
console.log('after makeKeyPairs pubkeyArray2: ' + pubkeyArray2);
});
} catch(err) {
console.log('err: ' + err);
}
function findKeyPair(){
Keypair.find({}, {pubkey: 1, _id: 0}, function(err, pubkeysObj) { //mongoose db
if (err) res.redirect('/');
console.log('inside findKeyPair pubkeysObj: ' + pubkeysObj);
return pubkeysObj; // ?????????
});
}
function makeKeyPairs(pubkeysObj3){
console.log('inside makeKeyPairs: pubkeysObj3:' + pubkeysObj3);
var pubkeyArray = [];
pubkeyArray = Object.keys(pubkeysObj3).map(function(_) { return pubkeysObj3[_].pubkey; })
return pubkeyArray; // ????
}
The output is:
before findKeyPair
inside findKeyPair pubkeysObj: { pubkey: 'n2eTmd37KTGhRZNJsf9tfVdCG1YejciETu' },{ pubkey: 'n2cBvz74bMGUf35gAdnSksbBnW1m4HfCmg' }
Would you be open to using wait.for?
I rewrote my code using "wait.for" and now I can receive the object KeypairObj from the database and pass it to the next function makeKeyPairs.
Inside this function I can print my array (pubkeyArray) but
I can't get the returned value (pubkeyArray2) and the last line of the function findKeyPair is not executed.
here is the new code:
var wait = require('wait.for');
var Keypair = require('./app/models/Keypair');
try {
// launch a new fiber
wait.launchFiber(findKeyPair, Keypair);
}
catch(err) {
console.log('err' + err);
}
function findKeyPair(Keypair){
var KeypairObj = wait.forMethod(Keypair,'find', {}, {pubkey: 1, _id: 0});
console.log('1: ' + KeypairObj.toString());
var pubkeyArray2 = wait.for(makeKeyPairs, KeypairObj);
console.log('3: pubkeyArray2: ' + pubkeyArray2); // not executed !!!
}
function makeKeyPairs(pubkeysObj3){
pubkeyArray = Object.keys(pubkeysObj3).map(function(_) { return pubkeysObj3[_].pubkey; });
console.log('2: pubkeyArray: ' + pubkeyArray);
}
and the output:
1: { pubkey: 'n2eTmd37KTGhRZNJsf9tfVdCG1YejciETu' },{ pubkey: 'n2cBvz74bMGUf35gAdnSksbBnW1m4HfCmg' }
2: pubkeyArray: n2eTmd37KTGhRZNJsf9tfVdCG1YejciETu,n2cBvz74bMGUf35gAdnSksbBnW1m4HfCmg

NODE.JS function callback to render page

I have a function getthem() that checks a mongo db for listings and returns name,streamurl for it.
I pass those as var stream to the renderme that renders the /dashboard page.
My problem is that i get the console.log("END OF FIND:"+JSON.stringify(stream))
to show my test input, but nothing goes to the render.
im using ejs to render. How can i get the result passed to the page ?
router.get('/dashboard', function (req, res) {
var foo = getthem();
function getthem() {
var group = "tesint";
console.log('geting for group : ' + group);
var mdlListings = require('../models/listings.js');
var myresult = "tet";
mdlListings.find({}, "name streamurl", function (err, data) {
if (err) {
console.error(err);
return;
}
if (data === null) {
console.log("No results");
return;
}
var stream = { };
data.forEach(function (streams) {
console.log("Got " + streams.name + " " + streams.streamurl);
stream[streams.name] = streams.streamurl;
// stream += 'name: '+streams.name+'},{streamurl: '+streams.streamurl;
// console.log("stram arry "+stream[streams.name] )
console.log("END OF FIND:"+JSON.stringify(stream))
}, renderme(stream));
// console.log("Result:", votes);
//var myresult = Object.keys(stream).map(function (name) {
// return { name: name, url: stream[name] };
//})
console.log("before return stream "+stream);
return stream;
});
}
function renderme(resa) {
console.log("RESA"+JSON.stringify(resa))
var resa = JSON.stringify(resa);
res.render('dashboard', {
title: 'Dashboard',
user: req.user,
listing: resa
}
)
}
You're passing the result of renderme(stream) as a second argument to forEach(). renderme(stream) is then evaluated immediately before your forEach() callback is called, when stream is still an empty object. My guess is you want something like this:
data.forEach(function (streams) {
console.log("Got " + streams.name + " " + streams.streamurl);
stream[streams.name] = streams.streamurl;
console.log("END OF FIND:"+JSON.stringify(stream))
});
renderme(stream);
Actually i figure that why would i pass the function as i could just do whatever i need to directly in there.
That worked perfectly, thanks for the tip.
data.forEach(function (streams) {
console.log("Got " + streams.name + " " + streams.streamurl);
stream[streams.name] = streams.streamurl;
});
res.render('dashboard', {
title: 'Dashboard',
user: req.user,
listing: data
}
)

Resources