how to stop process nodejs within promises - node.js

I've created nodejs to trigger(with cronjobs) firebase realtime database as follow:
var db = admin.database();
var ref = db.ref('myusers');
var promises = [];
function updateUnlocked(isLocked, locked, msisdn) {
return new Promise(function (resolve, reject) {
if (isLocked === 1) {
var startDate = moment(locked);
var endDate = moment();
var result = endDate.diff(startDate, 'minutes');
if (result > 5) {
var ref = db.ref('myusers/' + msisdn);
ref.update({isLocked: 2});
}
}
resolve('done');
});
}
ref.once('value', function(snapshot) {
snapshot.forEach(childSnapshot => {
promises.push(updateUnlocked(childSnapshot.val().isLocked, childSnapshot.val().locked, childSnapshot.key));
});
});
Promise.all(promises).then(function(data) {
console.log(data);
}).catch(function(err) {
console.log('error');
});
Please let me know where can I add process.exit(). Thanks.

You must wait for the "once" callback to get executed. Else the promise array is empty and the process could exit immediately.
var db = admin.database();
var ref = db.ref('myusers');
function updateUnlocked(isLocked, locked, msisdn) {
...
}
ref.once('value', function(snapshot) {
const promises = snapshot.map(childSnapshot => {
return updateUnlocked(childSnapshot.val().isLocked, childSnapshot.val().locked, childSnapshot.key);
})
Promise.all(promises).then(() => {
console.log('done')
process.exit(0)
}).catch(err => {
console.log('error', err)
process.exit(1)
})
});
Demonstrating the control flow.
setTimeout(() => {
const x = [1, 2, 3]
const promises = x.map(i => {
return new Promise(resolve => resolve(i))
})
Promise.all(promises).then(() => {
console.log('done. process.exit(0) here')
})
}, 200)

If you want to exit on successful completion then refer below code:
Promise.all(promises).then(function(data) {
console.log(data);
process.exit(0);
}).catch(function(err) {
console.log('error');
});
If you want to exit on error as well then add process.exit(1) in catch block.

Related

NodeJS no code running after worker code finishes

I'm having an issue with my worker code, currently i have some code that scans through two database tables and finds some matches and then adds some data from one table to the other creating a new table. This is a large set of data so i'm using worker threads to speed this up.
This is all working fine however once the worker threads are complete no other code runs i've tried adding the function LogData everywhere i can and it will not run i've even add the console.log("Finished building merge table") and that doesn't run either. Even the parentResolve does happen as i don't see the console.log("parentResolve") message.
if anyone can help me I would really appreciate it.
const calculateFactorialwithWorker = async () => {
const SCCM = await ProgramDev.find({ "program name": { $not: { $regex: ".*[(]KB*[)]*" } } }).limit(8000)
const sccmLength = SCCM.length
mongoose.connection.close()
return new Promise(async (parentResolve, parentReject) => {
const numbers = [...new Array(sccmLength)].map((_, i) => i);
const segmentSize = Math.ceil(sccmLength / userCPUCount);
const segments = [];
for (let segmentIndex = 0; segmentIndex < userCPUCount; segmentIndex++) {
const start = segmentIndex * segmentSize;
const end = start + segmentSize;
const segment = numbers.slice(start, end)
segments.push(segment);
}
try {
const results = await Promise.all(
segments.map(
segment =>
new Promise((resolve, reject) => {
const worker = new Worker(workerPath, {
workerData: segment,
});
worker.on('message', resolve);
worker.on('error', reject);
worker.on('exit', (code) => {
if (code !== 0)
reject(new Error(`Worker stopped with exit code ${code}`));
});
})
));
parentResolve(() => {
console.log("parentResolve")
})
} catch (e) {
parentReject(e)
}
});
};
calculateFactorialwithWorker().then(() => {
console.log("Finished building merge table")
LogData
})
Add if else block in worker exit event. When exit fired with code === 0 , there is no resolve/reject to handle it. The promises will not be resolved/rejected.
Ref. https://nodejs.org/api/worker_threads.html#worker_threads_event_exit
Also, I rewrite your codes a bit because some promises wrapper is unnecessary.
const calculateFactorialwithWorker = async () => {
try {
const SCCM = await ProgramDev.find({
"program name": { $not: { $regex: ".*[(]KB*[)]*" } },
}).limit(8000);
const sccmLength = SCCM.length;
const numbers = [...new Array(sccmLength)].map((_, i) => i);
const segmentSize = Math.ceil(sccmLength / userCPUCount);
const segments = [];
for (let segmentIndex = 0; segmentIndex < userCPUCount; segmentIndex++) {
const start = segmentIndex * segmentSize;
const end = start + segmentSize;
const segment = numbers.slice(start, end);
segments.push(segment);
}
const promises = segments.map(
segment =>
new Promise((resolve, reject) => {
const worker = new Worker(workerPath, {
workerData: segment,
});
worker.on("message", resolve);
worker.on("error", reject);
worker.on("exit", code => {
if (code !== 0) {
reject(new Error(`Worker stopped with exit code ${code}`));
} else {
resolve();
}
});
})
);
await Promise.all(promises);
} catch (err) {
throw new Error(err);
}
};
calculateFactorialwithWorker()
.then(() => {
console.log("Finished building merge table");
LogData();
})
.catch(console.log)
.finally(() => {
mongoose.connection.close();
});

Return result from python script in Node JS child process

Im trying to return the value from a python script from a nodejs child process and i just cant seem to get it to work, it prints in the console using console.log correctly as it should but only returns undefined, i was wondering if there is a way to directly return that value, or to parse the console.log results into a string.
var sys = require('util');
module.exports = function() {
this.getPlay = function getPlaylist(name) {
const childPython = spawn('python' ,['main.py', name]);
var result = '';
childPython.stdout.on(`data` , (data) => {
result += data.toString();
});
childPython.on('exit' , () => {
console.log(result);
});
}};
Python script is empty for now and prints "Hello 'name' "
Edit:
I tried to use promises and here is what i have:
(async function(){
function test(name) {
return new Promise((resolve , reject) => {
const childPython = spawn('python' ,['main.py', "He"]);
var result = '';
childPython.stdout.on(`data` , (data) => {
result += data.toString();
});
childPython.on('close' , function(code) {
t = result
resolve(result)
});
childPython.on('error' , function(err){
reject(err)
});
})};
var t;
await test(name);
console.log(t);
return t;
})();
Define it like this.
function getPlaylist(name) {
return new Promise((resolve , reject) => {
const childPython = spawn('python' ,['main.py', name]);
var result = '';
childPython.stdout.on(`data` , (data) => {
result += data.toString();
});
childPython.on('close' , function(code) {
resolve(result)
});
childPython.on('error' , function(err){
reject(err)
});
})
};
Remeber to use try...catch for it it gets rejected. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/try...catch
async function runTest() {
try {
const playList = await getPlaylist();
console.log(playList);
} catch (err) {
}
}
runTest()
const {spawn} = require('child_process');
const getPythonScriptStdout = (pythonScriptPath) => {
const python = spawn('python', [pythonScriptPath]);
return new Promise((resolve, reject) => {
let result = ""
python.stdout.on('data', (data) => {
result += data
});
python.on('close', () => {
resolve(result)
});
python.on('error', (err) => {
reject(err)
});
})
}
getPythonScriptStdout('./python.py').then((output) => {
console.log(output)
})
python.py file
print("hi from python")

Can't return data from callback function at NodeJS

When i create new variable and assign callback function, But data cannot return from callback function. Undefined is occurring at new variable.
const nedb = require('nedb');
const user = new nedb({ filename: './builds/database/users.db', autoload: true });
var s = user.find({}, function (err,docs) {
if(docs.length == 0) {
var data = false;
} else {
var data = docs;
}
return data;
});
console.log(s);
var s is undefined! ....
You are mixing up callback and Promise which are two different way to handle asynchronous calls.
I recommend you to use of Promises because they are simpler and the present and future of javascript.
Using async/await which is the next step after Promises
const user = {
find: () => ['jon', 'kalessi', 'jorah'],
};
async function getUsers() {
return (await user.find({})) || [];
}
async function myJob() {
const users = await getUsers();
console.log(users);
// Put your next code here
}
myJob();
Full promise :
const user = {
find: () => new Promise((resolve) => resolve(['jon', 'kalessi', 'jorah'])),
};
user.find({})
.then((docs = []) => {
console.log(docs);
// Put you next code here, you can use of the variable docs
})
.catch((err) => {
console.log(err);
});
Full callback :
const user = {
find: (_, callback) => callback(false, ['jon', 'kalessi', 'jorah']),
};
user.find({}, (err, docs = []) => {
if (err) {
console.log(err);
} else {
console.log(docs);
// Put you next code here, you can use of the variable docs
}
});
I think user.find returning the promise. you can do like this.
const nedb = require('nedb');
const user = new nedb({ filename: './builds/database/users.db', autoload: true });
var s = user.find({}, function (err,docs) {
if(docs.length == 0) {
var data = false;
} else {
var data = docs;
}
return data;
});
Promise.all(s)
.then(result => {
console.log(result);
});
Otherwise you can also use await Like this:
async function abc(){
const nedb = require('nedb');
const user = new nedb({ filename: './builds/database/users.db', autoload: true });
var s = await user.find({}, function (err,docs) {
if(docs.length == 0) {
var data = false;
} else {
var data = docs;
}
return data;
});
}
because await worked with async thats why i put it into async function.

Exporting a function declared inside asynchronous function

I have a file in which mongoose is setup
const keys = require('../chat/config/keys');
const mongoose = require('mongoose');
const dbURI = keys.mongoURI;
mongoose.connect(dbURI, { useNewUrlParser: true });
mongoose.set('debug', true);
let fetchVideo;
mongoose.connection.once('open', function () {
console.log('Mongoose default connection open to ' + dbURI);
let connectToDB = mongoose.connection.db;
let videoChatDB = connectToDB.collection('videochat');
fetchVideo = ({ id }) => {
if (id !== '100') {
videoChatDB.findOne({'studentID': parseInt(id)}).then((user) => {
if (user) {
console.log(user);
return true;
} else {
console.log(user);
return false;
}
});
}
}
});
module.exports = { fetchVideo };
And I am requiring that file inside my index.js file like so:
let db = require('./db');
In my index file I have a socket connection and I need to check the database when a new user comes.
socket.on('new-user', async (user) => {
let checkAvail = await db.fetchVideo(user);
});
But I am getting this error:
TypeError: db.fetchVideo is not a function
I am guessing it is undefined since it is declared inside an asynchronous function.
How would I make this to work?
Because the function is created asynchronously, one option is to export a Promise that resolves to fetchVideo function. Because mongoose.connection.once is callback-based, you'll have to transform it into a Promise.
If you want fetchVideo to resolve to something (rather than nothing), you also have to properly chain the findOne call with the promise chain; to fix that, return videoChatDB.findOne....
const fetchVideoProm = new Promise((res, rej) => {
mongoose.connection.once('open', function () {
console.log('Mongoose default connection open to ' + dbURI);
let connectToDB = mongoose.connection.db;
let videoChatDB = connectToDB.collection('videochat');
const fetchVideo = ({ id }) => {
if (id !== '100') {
return videoChatDB.findOne({'studentID': parseInt(id)}).then((user) => {
if (user) {
console.log(user);
return true;
} else {
console.log(user);
return false;
}
});
}
}
res(fetchVideo);
});
});
module.exports = { fetchVideoProm };
Consume it by awaiting the creation of the fetchVideo function, and then calling it:
socket.on('new-user', async (user) => {
const fetchVideo = await db.fetchVideoProm;
const checkAvail = await fetchVideo(user);
});

NodeJS Promise and Async Problems (Firebase)

The problem is with the promises and the async function. "All moved" is supposed to be logged after everything in async.each is done. But nothing is ever logged.
Here is my exports functions:
var courier_id = data.ref.parent.key;
return admin.database().ref("firewall_queue/"+courier_id+"/orders").once('value',function(orders){
//console.log(Object.keys(orders.val()));
async.each(Object.keys(orders.val()), function (order, callback) {
if(order != "none") {
return moveToWaitingFromFirewall(order).then(callback())
}
},
function (err) {
console.log("All moved");
return admin.database().ref("/firewall_queue/"+courier_id+"/orders/").remove().then(()=>{
return pushToPending(courier_id,data.ref.key);
})
});
})
Here is my moveToWaitingFromFirewall function:
function moveToWaitingFromFirewall(order_id){
var order = {};
order.id = order_id;
var promises = [];
promises.push(new Promise((resolve) => {
admin.database().ref("orders/"+order_id+"/zone").once('value').then(function(zone){
order.zone = zone.val();
resolve();
})
}))
promises.push(new Promise((resolve) => {
admin.database().ref("orders/"+order_id+"/time_order_placed").once('value').then(function(time_order_placed){
order.time = time_order_placed.val();
resolve();
})
}))
//grab zone and time first
return Promise.all(promises).then(()=>{
return admin.database().ref(order.zone+"/wait_order_queue/"+order.id).set(order.time);
})
}
JSON Firebase
"c98" : {
"orders" : {
"0333" : 123123,
"0345" : 12,
"0911" : 123,
"none" : "none"
}
Study this a little bit, and maybe apply to your current code.
Imagine admin.database().ref("orders/"+order_id+"/time_order_placed").once('value') is like delay(time)
// let delay = time => new Promise(res=>setTimeout(res,time));
let delay = function(time){
return new Promise(function(resolve,reject){
setTimeout(function(){
resolve();
},time);
});
}
let myPromise = function(order){
return Promise.all([
delay(500),
delay(500),
delay(1000).then(function(){
console.log('Order complete: ',order);
return; // returns undefined, so cb doesn't pass anything to cb(err), but use ()=>cb() to avoid this anyways.
})
]);
}
let orders = [1,2,3];
async.each(orders,function(order,cb){
myPromise(order)
.then(()=>cb())
.catch(err=>cb(err));
},function(err,data){
if(err){
console.log('Err',err);
}else{
console.log('all Finished');
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/async/2.6.0/async.js"></script>

Resources