NodeJS - Nested Promise inside a for loop - node.js

I am trying to do a call which retrieves a list of categories. Inside this call I want to loop through the categories and retrieve the items for each category and return them all together. My call retrieves the categories perfectly before I added the loop to retrieve the items.
To double check my call to another controller works, I added a proof of concept block of code which you can see below is commented out. So I know it isn't the call to an external class.
Here is my code:
'use strict';
var mongoose = require('mongoose'),
MenuCategory = mongoose.model('MenuCategory');
module.exports = function(menuItemController) {
var mod = {
listEntireMenu(req, res) {
return new Promise(function(resolve, reject) {
var entireMenu = [];
MenuCategory.find({}, function(err, menuCategories) {
if (err) {
return reject(err)
} else {
//---------------------------
// PROOF OF CONCEPT THAT CALL TO OTHER CONTROLLER WORKS
//---------------------------
//
// var categoryWithItems = menuCategories[0].toObject();
// req.body.menuCategoryID = categoryWithItems._id;
// menuItemController.listAllMenuItemsByCategory(req, res).then((menuItems) => {
// if(menuItems)
// {
// return resolve(menuItems);
// }
// else
// {
// return { success: false }
// }
// });
//-----------------------------
for (var i = 0; i < menuCategories.length; i++) {
var categoryWithItems = menuCategories[i].toObject();
var subItems = [];
req.body.menuCategoryID = categoryWithItems._id;
menuItemController.listAllMenuItemsByCategory(req, res).then((menuItems) => {
if(menuItems)
{
subItems = menuItems;
}
else
{
return { success: false }
}
});
categoryWithItems.tester = { "itemsList" : subItems };
entireMenu.push(categoryWithItems);
}
return resolve(entireMenu)
}
});
}).then((menuCategories) => {
if(menuCategories)
{
return menuCategories
}
else
{
return { success: false }
}
});
},
}
return mod;
};
What I actually get returned is this :
[
{
"_id": "5ed16fxxxxxxxx95676e37",
"locationID": "5ed16xxxxxxxx7295676e36",
"menuCategoryName": "Category One",
"Created_date": "2020-05-29T20:26:34.991Z",
"__v": 0,
"tester": {
"itemsList": []
}
},
{
"_id": "5ed170xxxxxx95676e38",
"locationID": "5ed16xxxxxxxx7295676e36",
"menuCategoryName": "Category Two",
"Created_date": "2020-05-29T20:26:48.799Z",
"__v": 0,
"tester": {
"itemsList": []
}
}
]
Here is the call from the route.js :
app.get('/api/listEntireMenu', (req, res) => {
menuCategoryController.listEntireMenu(req, res).then(menuCategories => res.json(menuCategories));
})
It never writes the subItems into the object. Is this an async issue or something else? I am not sure how to solve this.
Thanks in advance.

i believe the reason the result of your call to resolve is being returned before the requests are able to complete...for this you need to wait until all the promises or requests have finished properly and returned.
There are two ways you can do this: you could either run them one by one and wait for each one to finish first or run them all concurrently until all of them are done.
Ofcourse the fastest way to do it would be to run them all concurrently so lets go for that way:
so to start, let us not use the for loop and instead remap the iterable array menuCategories to promises of the request, we will use your proof of concept code to make the array of promises
//...
Promise.all(
menuCategories.map((category) => {
let category_with_items = category.toObject();
req.body.menuCategoryID = category_with_items._id;
// here we need to return this since its the promise we are remapping to
return menuItemController.listAllMenuItemsByCategory(req, res)
.then((menuitems) => {
if(menuItems) {
return menuitems;
}
throw 'No menu items found'
});
});
)
// each promise will return menuitems so we have to wait for all the promises to complete
// then with the results of each promise we push the items into the entire menu
.then((itemslist) => {
itemslist.forEach((items) => entireMenu.push(items));
return entireMenu;
})
// lastly we need to handle any errors from the promises
.catch((error) => { success: false });
//...
So now we have...
listEntireMenu(req, res) {
return MenuCategory.find({}, function(err, menuCategories) {
if (err) {
throw err
} else {
entireMenu = [];
return /* the promise all call from above will go right here */;
}
}
I hope it works out, thanks...

Related

Issue with useMutation with await and promise

I am performing the useMutation operation in the innermost loop and want to check the remaining cost upon every mutation. But it gets checked after all the mutations which is a problem because for some reason even if all the mutations get done(When the cost is under limits), It calls the .then() part for cost-checking and waiting for unknown reason.
Edit: I also noticed that even though the program is waiting again and again, the network status of chrome shows that all the mutations have happened and only the query of handleDiscountMore i.e. fetchMore is pending
const { loading, error, data, fetchMore, extensions, refetch } = useQuery(GET_COLLECTION, {
variables: { "id": coll.collection.id }
});
const [updatePrice] = useMutation(UPDATE_PRICE);
const redirectToModify = async (data, totalProducts) => {
wait(20000);
var cursor, fetchCount;
fetchCount = data.collection.products.edges.length;
totalProducts -= fetchCount;
data.collection.products.edges.map(async(product) => {
const results = await Promise.all(product.node.variants.edges.map(variant => {
if (selected == 'curr_price') {
//do stuff
}
else {
//do stuff
}
const productVariableInput = {
//Object
};
updatePrice({ variables: { input: productVariableInput } }).then(({ data, extensions }) => {
console.log("Remaining", extensions.cost.throttleStatus.currentlyAvailable)
console.log(data)
if (extensions.cost.throttleStatus.currentlyAvailable < 100) {
console.log("WAITING")
wait(18000);
}
}).catch(e => {
console.log(e)
})
console.log("AFTER")
return 0;
}))
})
if (totalProducts > 0) {
console.log("Calling")
wait(15000);
handleDiscountMore(data, cursor, totalProducts)
}
};
//Below function is Just for reference. It gets called before checking the throttleStatus above. afaik there's no problem with this
const handleDiscountMore = (data, cursor, pc) => {
console.log("Call received")
fetchMore({
variables: {
"id": data.collection.id,
"cursor": cursor
},
updateQuery: (
previousResult,
{ fetchMoreResult }
) => {
console.log("adding", fetchMoreResult);
redirectToModify(fetchMoreResult, pc);
// return fetchMoreResult;
}
})
}
Your map of maps is evaluating all promises at exactly the same time. Here's a cleaned up example that uses a nested for loop instead, which will wait for each request to finish before starting the next (note: I couldn't run it to test, so there's probably some bugs, but the idea is there):
const id = coll.collection.id;
const { loading, error, data, fetchMore, extensions, refetch } = useQuery(GET_COLLECTION, {
variables: { id }
});
const [updatePrice] = useMutation(UPDATE_PRICE);
// Given a product, returns a promise that resolves when all variants are processed
async function process_product(product){
const variants = product.node.variants.edges;
for (let i = 0; i < variants.length; i++){
await process_variant(variants[i]);
}
}
// Given a variant, returns a promise after the product is processed
async function process_variant(variant){
if (variant) {
console.log('doing stuff')
}
else {
console.log('doing other stuff')
}
const productVariableInput = {};
const variables = { input: productVariableInput };
try {
const {data, extensions} = await updatePrice({ variables });
const remaining_throttle = extensions.cost.throttleStatus.currentlyAvailable;
console.log("Remaining", remaining_throttle)
console.log(data)
// Change to a while loop to make sure you actually wait until resources are available
if (remaining_throttle < 100) {
console.log("WAITING")
await wait(18000);
}
} catch (e) {
console.log('error:', e);
}
console.log("AFTER")
return 0;
}
const redirectToModify = async (data, totalProducts) => {
await wait(20000);
let cursor;
const products = data.collection.product.edges;
totalProducts = totalProducts - products.length;
// Wait for all products to finish processing
for (var i = 0; i < products.length; i++){
await process_product(products[i]);
}
if (totalProducts > 0) {
console.log("Calling")
await wait(15000);
handleDiscountMore(data, cursor, totalProducts)
}
};
function updateQuery(previousResult, { fetchMoreResult }){
console.log("adding", fetchMoreResult);
redirectToModify(fetchMoreResult, pc);
return fetchMoreResult;
}
//Below function is Just for reference. It gets called before checking the throttleStatus above. afaik there's no problem with this
function handleDiscountMore(data, cursor, pc) {
console.log("Call received")
const variables = { id: data.collection.id, cursor };
fetchMore({ variables, updateQuery })
}

Using Promise.all() with SequeliseJS

I'd like to check if uploading files are used in my database. So I'd like to list all files in the "uploads" folder and then check with SequelizeJs if item are finded with the right property.
My code seems not working as espected :
var promises = [];
fs.readdir('./public/uploads', (err, files) => {
if (!err) {
promises = files.filter(function(file) {
if (file !== 'csv' && file !== '.gitignore') {
// vérification dans FileModel
return models.FileModel.findOne({ where: { name: '/uploads/' + file } }).then(function(findedFile) {
if (!findedFile) {
return Promise.resolve(file).then(function() {
// Vérification dans VehiclePhotoModel
return models.VehiclePhotoModel.findOne({ where: { name: '/uploads/' + file } }).then(function(findedFile) {
if (!findedFile) {
return Promise.resolve(file);
}
});
});
}
});
}
});
}
});
Promise.all(promises).then(function(unusedFiles) {
response.render('file/_checkUnusedFiles', {
_layoutFile: false,
unusedFiles: unusedFiles
});
});
Edit #1 :
I've mixed up your code that doesn't work for me but I still get an issue, the Promise.resolve() is not returning the string name file.
const fileModels = [
{ model: models.FileModel, property: 'name' },
{ model: models.VehiclePhotoModel, property: 'name' }
];
function _checkUnusedFiles(request, response) {
var promises = [],
files = _.remove(fs.readdirSync('./public/uploads'), function(file) {
return file !== 'csv' && file !== '.gitignore';
});
promises = _.map(files, function(file) {
return fileModels.map(function(fileModel) {
var where = {};
where[fileModel.property] = file;
return fileModel.model.findOne({ where: where }).then(function(findedItem) {
if (!findedItem) {
return Promise.resolve(file);
}
});
});
});
Promise.all(promises).then(function(unusedFiles) {
response.render('optimizer/_checkUnusedFiles', {
_layoutFile: false,
unusedFiles: unusedFiles
});
});
}
With the above code soon you get into callback hell, which will result in issues like the ones you have mentioned. Anyways, so the problem is as follows
files.filter returns
<string[]> | <Buffer[]> | <fs.Dirent[]>
taken from documentation:https://nodejs.org/api/fs.html#fs_fs_readdir_path_options_callback
a better approach would be to loop and then do something like promises.append(...)
even better approach break down your code using async await to avoid callback hell and issues like this
You really don't need Promise.all in your case as it might complicated things even further and could be a performance bottleneck.
Something like this should work fine
const fs = require('fs')
const path = require('path')
// Mocking SequeliseJS (You can remove this and replace in code as well with original models
const modelsMock = {
FileModel: {
findOne: (query) => {
return new Promise((resolve, reject) => {
// rand will just randomize result between true and false
let rand = Math.floor(Math.random() * Math.floor(2))
resolve(rand == 1 ? resolve(true) : resolve(false))
})
}
},
VehiclePhotoModel: {
findOne: (query) => {
return new Promise((resolve, reject) => {
// rand will just randomize result between true and false
let rand = Math.floor(Math.random() * Math.floor(2))
resolve(rand == 1 ? resolve(true) : resolve(false))
})
}
}
}
run()
async function run() {
let promises = []
let existFiles = []
let doesntExistFiles = []
// If the goal is to use readdir async then uncomment the following and comment let files = fs.readdirSync('./public/uploads')
/*
const util = require('util')
const readdir = util.promisify(fs.readdir);
let files = await readdir('./public/uploads')
*/
let files = fs.readdirSync('./public/uploads')
// Filter files: (using array.filter is pretty useless to us here since we can't run it async unless we want to promisify it which there are plenty of examples out there, for now we will stick with good old fashion loop)
for(var i = 0; i < files.length; i++) {
const file = files[i]
if(path.extname(file) !== '.csv' && path.extname(file) !== '.gitignore') {
try {
let exist = await checkIfFileExist(file, modelsMock)
exist === true ? existFiles.push(file) : doesntExistFiles.push(file)
} catch (e) {
// Handle error here
}
}
}
response.render('file/_checkUnusedFiles', {
_layoutFile: false,
unusedFiles: unusedFiles //Note this will break the code as unusedFiles is undefined, I really dont know what is this variable hence I didn't change it but feel free to change it as you see it appropriate.
});
}
async function checkIfFileExist(file, models){
let query = `{ where: { name: '/uploads/' + ${file} } }`
try {
let existInFiles = await models.FileModel.findOne(query)
if(!existInFiles) {
let existInVehicle = await models.VehiclePhotoModel.findOne(query)
existInVehicle ? return true : return false
} else {
return true
}
}
catch(e) {
throw e
}
}
here is the full example working on Repl.it
https://repl.it/repls/DramaticAwfulSpreadsheets#index.js
EDIT1:
Like I mentioned in the comments I don't really suggest what you are doing (My opinion at least :)); however, if you flatten your array everything should be fine.
const fileModels = [
{ model: models.FileModel, property: 'name' },
{ model: models.VehiclePhotoModel, property: 'name' }
];
function _checkUnusedFiles(request, response) {
var promises = [],
files = _.remove(fs.readdirSync('./public/uploads'), function(file) {
// I think you want to check for extension here and not the file name? if so use this
// return (path.extname(file) !== '.csv' && path.extname(file) !== '.gitignore') //Make sure to require('path')
return file !== 'csv' && file !== '.gitignore';
});
promises = _.map(files, function(file) {
return fileModels.map(function(fileModel) {
var where = {};
// Your query seems wrong? at least different from last time. If it is intentional then you are good otherwise I think you meant to do
// where[fileModel.property] = `/uploads/${file}`
where[fileModel.property] = file;
return fileModel.model.findOne({ where: where }).then(function(findedItem) {
if (!findedItem) {
return Promise.resolve(file);
}
});
});
});
// Your promises array is more like a 2d array because each file will map to an array of 2 promises
// So if you flatten it, you should get a 1D promises array
promises = promises.flat()
Promise.all(promises).then(function(unusedFiles) {
response.render('optimizer/_checkUnusedFiles', {
_layoutFile: false,
unusedFiles: unusedFiles
});
});
}
If you don't flatten the output of promises looks something like the following
promises =
[
[ Promise { <pending> }, Promise { <pending> } ],
[ Promise { <pending> }, Promise { <pending> } ]
]
Each entry is a file which has 2 promises for each model
So when you do Promise.all(promises) it really doesn't know how interpret that in 2D arrays; However, when you flatten it, your output looks something similar to:
promises =
[
Promise { <pending> },
Promise { <pending> },
Promise { <pending> },
Promise { <pending> }
]
Now keep in mind unusedFiles output may look weird and that is because not every promise will actually resolve to something meaningful, at least that is what you are mapping.

expressJs - Wait for a promise inside a loop

Novice question; I need to create a conditional loop which makes a call to the database. The value returned from the promise determines if I should break out of the loop as follows:
let id, caged;
do {
caged = false;
id = models.Cage.generateId();
caged = models.Cage.findOne({ where: { dispatchLabelId: id } });
} while( caged );
Can anybody please advise how I can structure my code?
You can do that using promises and recursive function calls:
let getCage = () => {
return models.Cage
.generateId()
.then(id => models.Cage.findOne({ where: { dispatchLabelId: id } }))
.then(caged => {
if (caged) {
return caged;
}
return getCage();
});
}
In the case if you can use node.js v7.6 or higher you can avoid using recursive function calls and implement this using async/await:
let getCage = async () => {
try {
do {
let id = await models.Cage.generateId();
let caged = await models.Cage.findOne({ where: { dispatchLabelId: id } });
if (caged) {
return caged;
}
} while (true);
} catch (err) {
console.log(err);
}
}

returning Mongoose query result from Async call

I'm working on a problem where I need to query the db for an instance of a Voter, and use that instance to update an Election, returning to the original function whether that update was successful or not. My code currently looks like this:
function addCandidatesToElection(req, res) {
let electionName = req.body.electionName;
let candidates = req.body.candidates;
let addedCandidatesSucessfully = true;
for(let i=0; i<candidates.length; i++) {
addedCandidatesSucessfully = _addCandidateToElection(electionName, candidates[i]);
console.log("added candidates sucessfully:" + addedCandidatesSucessfully);
}
if(addedCandidatesSucessfully) {
res.send("createElection success");
} else {
res.send("createElection fail");
}
}
which calls this function:
function _addCandidateToElection(electionName, candidateName) {
async.parallel(
{
voter: function(callback) {
Voter.findOne({ 'name' : candidateName }, function(err,voter) {
callback(err, voter);
});
}
},
function(e, r) {
if(r.voter === null){
return 'Voter not found';
} else {
Election.findOneAndUpdate(
{'name': electionName },
{$push: { candidates: r.voter }},
{new: true},
function(err, election) {
if(err){ return err; }
return (election) ? true : false;
});
}
}
);
}
I've already tried printing out the Voter instance(r.voter) to check if it exists (it does), and also printing out the election object returned by the mongoose call, which also works. However, I'm getting a null value in the
addedCandidatesSucessfully = _addCandidateToElection(electionName, candidates[i]);
line, regardless of the result of the call. I think it has to do with the mongoose call returning a local value which is never returned to the function that called _addCandidateToElection, but I don't know how I should return that. I've tried putting control flags such as
let foundAndUpdatedElection = false;
on the first line of _addCandidateToElection and updating it inside the Mongoose query's callback, but apparently it doesn't change.
How should I return the result of the query to the addCandidatesToElection function?
You should probably 'promisify' your code to help you better deal with the asynchronous nature of js. Try the following instead of your example:
function findVoter(candidateName) {
return new Promise(function(resolve, reject) {
Voter.findOne({ 'name' : candidateName }, function(err,voter) {
if(error) {
reject(error);
} else {
resolve(voter);
}
});
});
}
function addCandidateToElection(electionName, candidateName) {
return findVoter(candidateName).then(function(voter) {
return new Promise(function(resolve, reject) {
Election.findOneAndUpdate(
{'name': electionName },
{$push: { candidates: voter }},
{new: true},
function(err, election) {
if (err) {
reject(err);
} else {
resolve(!!election);
}
});
});
}
function addCandidatesToElection(req, res) {
let electionName = req.body.electionName;
let candidates = req.body.candidates;
let addedCandidatesSucessfully = true;
let candidatePromiseArray = [];
for(let i=0; i<candidates.length; i++) {
candidatePromiseArray.push(addCandidateToElection(electionName, candidates[i]));
}
Promise.all(candidatePromiseArray)
.then(function(results) {
console.log(results);
res.send('create election success');
})
.catch(function(error) {
console.error(error);
res.send('failed');
});
}
You will also no longer need to use the async library because promises are now native in ES6

Call synchronously recursively function in nodejs

I'm developing MEANJS project. Here a function which return array by fetch data recursively. Now, I have the problem that how to get that array.
Problem:-
let users A have properties is {_id:'001',rmUserId:'001'}, B:{_id:'002',rmUserId:'001'}, C {_id:'003',rmUserId:'002'}, D {_id:'003',rmUserId:'001'}, E {_id:'004',rmUserId:'009'}
if user A will login then allUnderUsers array have B,C,D users. That means all users have to follow an own hierarchy.
A
/ \
B D
/
C
Here is my code:-
module.exports.getUnderUsersByRm = function(currentUser, callback) {
try {
var allUnderUsers = [];
function __getUserByRmId(rmId) {
User.find({ rmUserId: rmId, isAlive: true, status: 'active' })
.exec(function(err, users) {
if (err)
return callback(err)
if (users.length > 0) {
users.forEach(function(ele, i) {
allUnderUsers.push(ele);
__getUserByRmId(ele.rmUserId);
});
} else {
return false;
}
})
}
__getUserByRmId(currentUser._id);
} catch (e) {
callback(e)
}
}
Here I need to get allUnderUsers array after all recursive function called.
I have use callback function like:-
....
...
__getUserByRmId(currentUser._id);
callback(null,'done');
.
.
but it throws an error i.e,
Error: Can't set headers after they are sent
.at ServerResponse.OutgoingMessage.setHeader (_http_outgoing.js:346:11)
at ServerResponse.header (/home/clsah/projects/LMS/node_modules/express/lib/response.js:719:10)
........ .......
If you take advantage of the promises built into the later versions of mongoose and surface a promise interface from your module, you can do this:
Simulated running code here: https://jsfiddle.net/jfriend00/zr6ynmsu/
module.exports.getUnderUsersByRm = function(currentUser) {
function __getUserByRmId(rmId) {
// return promise here
return User.find({ rmUserId: rmId, isAlive: true, status: 'active' }).exec().then(function(users) {
if (users.length > 0) {
let promises = [];
users.forEach(function(ele, i) {
promises.push(__getUserByRmId(ele.rmUserId));
});
// return promise which will chain it to original promise
// this is the key to getting the master promise to wait
// for everything to be done
return Promise.all(promises).then(results => {
// add in previous results
// flatten all the results together into a single array
// and remove empty results
results.unshift(users);
return [].concat.apply([], results.filter(item => item.length > 0));
});
} else {
return [];
}
});
}
return __getUserByRmId(currentUser);
}
And, then you would use it like this:
const someModule = require('yourModule');
someModule.getUnderUsersByRm(someUser).then(results => {
// process all results here
}).catch(err => {
// error here
});
If you still want your callback interface on getUnderUsersByRm, you can still do that (though if you're doing more than a few async calls, it really is worth using promises for all async operations):
module.exports.getUnderUsersByRm = function(currentUser, callback) {
function __getUserByRmId(rmId) {
// return promise here
return User.find({ rmUserId: rmId, isAlive: true, status: 'active' }).exec().then(function(users) {
if (users.length > 0) {
let promises = [];
users.forEach(function(ele, i) {
promises.push(__getUserByRmId(ele.rmUserId));
});
// return promise which will chain it to original promise
// this is the key to getting the master promise to wait
// for everything to be done
return Promise.all(promises).then(results => {
// add in previous results
// flatten all the results together into a single array
// and remove empty results
results.unshift(users);
return [].concat.apply([], results.filter(item => item.length > 0));
});
} else {
return [];
}
});
}
__getUserByRmId(currentUser).then(result => {
callback(null, result);
}).catch(err => {
callback(err);
});
}
If your user tree is circular, then you can protect against an infinite loop by keeping track of all the visited users. You need some sort of unique key that identifies each user. Since I don't know what that is in your program, I will assume the user you are passing in is already an id. Any property that uniquely identifies the user will work in this scheme:
module.exports.getUnderUsersByRm = function(currentUser) {
let visitedUsers = new Set();
function __getUserByRmId(rmId) {
// return promise here
return User.find({ rmUserId: rmId, isAlive: true, status: 'active' }).exec().then(function(users) {
if (users.length > 0) {
let promises = [];
users.forEach(function(ele, i) {
// make sure we aren't already processing this user
// avoid circular loop
let userId = ele.rmUserId;
if (!visitedUsers.has(userId)) {
visitedUsers.add(userId);
promises.push(__getUserByRmId(userId));
}
});
// return promise which will chain it to original promise
// this is the key to getting the master promise to wait
// for everything to be done
return Promise.all(promises).then(results => {
// add in previous results
// flatten all the results together into a single array
// and remove empty results
results.unshift(users);
return [].concat.apply([], results.filter(item => item.length > 0));
});
} else {
return [];
}
});
}
return __getUserByRmId(currentUser);
}
I tried to implement the solution using async based approach. You may find it naive, but it should work.
function __getUserByRmId(rmId, cb) {
var allUnderUsers = [];
User.find({ rmUserId: rmId, isAlive: true, status: 'active' })
.exec(function(err, users) {
async.each(users, function(user, callback){
if (user._id != rmId){
// recursive call
__getUserByRmId(user._id, function(childUsers){
childUsers.forEach(function (childUser) {
allUnderUsers.push(childUser);
});
callback(); //intermediate callback for async call
});
} else { //condition check to avoid infinite loop
allUnderUsers.push(user);
callback(); //intermediate callback for-loop
}
}, function(err){
cb(allUnderUsers); //final callback with result
});
});
}
module.exports.getUnderUsersByRm = function(currentUser, callback) {
__getUserByRmId(currentUser._id, callback)
};
Logically, it should work. Please give a try and let me know, if there are any issue. For now, it returns array containing parent as well. e.g. [A, B, C, D] for your example.
Use async.until and maintain an array of element to be processed
var async = require('async');
module.exports.getUnderUsersByRm = function(currentUser, callback) {
try {
var allUnderUsers = [];
var usersToProcess = [currentUser._id]; // Array to track what was earlier done with recursion
async.until(function() { // Test function for async.until
return usersToProcess.length === 0;
}, function __getUserByRmId(callback2) { // fn for async.until
User.find({
rmUserId: usersToProcess.shift(), // Take first element of array
isAlive: true,
status: 'active'
})
.exec(function(err, users) {
if (err)
return callback2(err)
if (users.length > 0) {
users.forEach(function(ele, i) {
allUnderUsers.push(ele);
usersToProcess.push(ele.rmUserId);
// __getUserByRmId(ele.rmUserId); // To Remove
});
return callback2(); // Always call callback;
} else {
return callback2(); // Earlier: return false; Return some err argument if you want
}
})
}, callback); // Final callback for async.until
} catch (e) {
callback(e);
}
}
I'm pretty sure that you are getting that error because you run __getUserByRmId function (which inside calls the callback function if an error occurs, and then, besides anything that happen you call the callback function again, which may be sending multiple responses to one same request, and so on, setting headers multiple times even when the response was already sent.
I should have post this in the comments but don't have enough reputation to do so

Resources