Node.js How to restart Async.Series on error callback - javascript

I use Async utility module in my app. I have a question. How i can restart the async.series, when "get_data" stage return an error?
function get() {
console.log('App start');
async.series([
open_db,
get_data,
close_db
], function (err) {
console.log('App down');
})
};
function open_db(callback) {
mongoose.connect('mongodb://localhost/app', function (err) {
if (err) throw err;
console.log('App connect to DB');
callback();
});
};
function get_data(callback) {
if (err) {
console.log('Error')
callback();
} else {
console.log('Ok');
callback();
}
};
function close_db(callback) {
mongoose.disconnect(function() {
console.log('App disconnect from DB');
callback();
});
};
On "get_data" stage i use websockets.subscribe operations, and save data from another server to DB. When websocket connection down, i need to retry connection to server with some time interval

function query_data() {
async.series([
open_db,
get_data,
close_db
], function (err) {
if (err)
...
})
};
function open_db(callback, attempt_no) {
mongoose.connect('mongodb://localhost/app', function(err) {
if (!err)
return callback();
attemp_no = !attempt_no ? 1 : attempt_no + 1;
if (attempt_no > 5)
return callback(new Error('Maximum number of attempts exceeded'));
setTimeout(() => open_db(callback, attempt_no), 500);
});
};
function get_data(callback) {
if (err)
return callback(err);
// do-smth-with-data and call callback
};
function close_db(callback) {
mongoose.disconnect(callback);
};

Use async.retry
function all_get_data(cb) {
console.log('App start');
async.series([
open_db,
get_data,
close_db
], function (err) {
if (err) {
console.log('App down');
return cb(err)
}
return cb()
})
};
// try calling apiMethod 3 times, waiting 200 ms between each retry
async.retry({times: 3, interval: 200}, all_get_data, function(err, result) {
// do something with the result
});

Related

UNHANDLEDREJECTION Callback was already called in aysnc parallel

I am using async parallel to get data from db in parallel.
When every task is returning the data I am storing it in local object.
From index.js I am calling cacheService.js .
In cacheService.js I am loading data from mysql database and mongo database in to cache object.
Whenever I am doing npm run local run. I am getting following error.
UNHANDLEDREJECTION Error: Callback was already called.
This error is coming from loadMongoData method of cacheService.js.
I have followed other answers on stackoverflow like adding else part
Here is code for cacheService.js.
'use strict';
var cache = [];
class cacheService {
async init() {
await this.loadMongoData();
}
loadMongoData(env, callback1) {
const _this = this;
console.log('Inside loadMongoData')
async.parallel(
{
task1: function (callback) {
CriteriaDef.find({})
.lean()
.exec(function (err, criteriaDefs) {
if (err) {
console.log('Inside err 1')
logger.error('Error fetching CriteriaDef: ', util.inspect(err));
callback(err, null);
} else if (criteriaDefs) {
console.log('Inside criteriaDefs')
if (criteriaDefs.length && criteriaDefs.length > 0) {
console.log('Inside criteriaDefs 1')
global.CRITERIA_DEFS = criteriaDefs;
cache['criteria_defs'] = criteriaDefs;
}
callback(null, null);
}
});
},
task2: function (callback) {
groupDef
.find({})
.lean()
.exec(function (err, groupDefs) {
if (err) {
console.log('Inside err2')
logger.error('Error fetching groupDefs: ', util.inspect(err));
callback(null, err);
} else if (groupDefs) {
console.log('Inside ')
global.groupDefsWithRoles = groupDefs;
let _groupDefs = [];
_.each(groupDefs, function (groupDef) {
var data = {
value: groupDef._id,
label: `${groupDef._id}: ${groupDef.description}`
};
_groupDefs.push(data);
});
global.groupDefs = _groupDefs;
cache['groupDefs'] = _groupDefs;
logger.info('Loaded groupDefs: ', global.groupDefs.length);
callback(null, null);
}
});
},
task3: function (callback) {
jiraProjects.find({$or: [{archived: {$ne: true}}, {archived: {$exists: false}}]}).exec(function (err, jiraProjects) {
if (err) {
console.log('Inside error 3')
logger.error('Error fetching jiraProjects: ', err);
callback(null, err);
} else if (jiraProjects) {
console.log('Inside jira project')
let _jiraProjects = [];
_.each(jiraProjects, function (jiraProject) {
var data = {
value: jiraProject.key,
label: jiraProject.key,
issueType: jiraProject.issueType ? jiraProject.issueType : 'Bug'
};
_jiraProjects.push(data);
});
global.jiraProjectsList = _jiraProjects;
cache['jiraProjects'] = _jiraProjects;
logger.info('Loaded jira projects: ', global.jiraProjectsList.length);
callback(null, null);
}
});
},
task4: function (callback) {
console.log('Inside task4')
callback(null, null);
},
task5: function (callback) {
inputElements
.find({})
.lean()
.exec(function (err, inputElements) {
if (err) {
console.log('Inside error5')
logger.error('Error fetching inputElements: ', util.inspect(err));
callback(null, err);
} else if (inputElements) {
console.log('Inside inputelements')
global.INPUT_ELEMENTS_DEF = inputElements;
cache['INPUT_ELEMENTS_DEF'] = inputElements;
callback(null, null);
}
});
},
task6: function (callback) {
console.log('Inside task6')
sisp.loadProducts('', callback);
}
},
function (err, results) {
if (err) {
console.log('Inside final error')
logger.error("Something went wrong can't start the app: ", util.inspect(err));
callback1(null, err);
} else {
console.log('Inside final else')
logger.info('loaded all globals properly :)');
callback1(null, null);
}
}
)
}
}
export default new cacheService();
I think your problem cuz you use callback inside of promise.
Please change your code like this:
class cacheService {
async init() {
await new Promise((resolve, reject) => {
this.loadMongoData(env, (ignoreArg, error) => {
if (error) {
return reject(error);
}
resolve();
});
});
}
...
}
Tip: in the each task add statement else for call callback, because maybe your statement not handled and your code can't execute prefect
task1: function (callback) {
CriteriaDef.find({})
.lean()
.exec(function (err, criteriaDefs) {
if (err) {
console.log('Inside err 1')
logger.error('Error fetching CriteriaDef: ', util.inspect(err));
callback(err, null);
} else if (criteriaDefs) {
console.log('Inside criteriaDefs')
if (criteriaDefs.length && criteriaDefs.length > 0) {
console.log('Inside criteriaDefs 1')
global.CRITERIA_DEFS = criteriaDefs;
cache['criteria_defs'] = criteriaDefs;
}
callback(null, null);
} else {
callback(null, null);
}
});
},

How .on method in node js work

Can someone explain me below code snippet? Here how and when .on method with tags "error" and "close" executes when it is not emitted anywhere.
function start() {
amqp.connect(process.env.CLOUDAMQP_URL + "?heartbeat=60", function(err, conn) {
if (err) {
console.error("[AMQP]", err.message);
return setTimeout(start, 1000);
}
conn.on("error", function(err) {
if (err.message !== "Connection closing") {
console.error("[AMQP] conn error", err.message);
}
});
conn.on("close", function() {
console.error("[AMQP] reconnecting");
return setTimeout(start, 1000);
});
console.log("[AMQP] connected");
amqpConn = conn;
whenConnected();
});
}

Node.js async iteratee with timeout

Bit new to node.js and javascript. Attempting to have my foreach call a function that in turn does a remote call. I'd like there to be a delay between each but can't seem to work out where to put the set timeout.
I know I have my setTimeout in the wrong place below but putting it in there as an example.
var likeRecommendation = function (recommendation, callback) {
context.Client.like(recommendation._id, function (error, data) {
recommendation['drupal_user_uid'] = context.message.uid;
recommendation['drupal_user_uuid'] = context.message.uuid;
if (error) return callback(new Error('Could not like recommendations'));
context.broker.publish('saves_swipes_publication', recommendation, function (err, publication) {
if (err) return callback(new Error('Could queue swipes to save'));
publication.on('error', console.error);
});
console.log('Liked!');
return callback()
});
}
async.forEach(context.recommendations, likeRecommendation, function (error) {
if (!error) return done(null);
done(new Error('Could not like recommendations'));
});
}
See timeout, warning one of your callback was missing and one other was not well placed.
var likeRecommendation = function (recommendation, callback) {
context.Client.like(recommendation._id, function (error, data) {
recommendation['drupal_user_uid'] = context.message.uid;
recommendation['drupal_user_uuid'] = context.message.uuid;
if (error)
setTimeout(function(){return callback(new Error('Could not like recommendations'))}, 100);
else {
context.broker.publish('saves_swipes_publication', recommendation, function (err, publication) {
if (err)
setTimeout(function(){return callback(new Error('Could queue swipes to save'))}, 100);
else
{
publication.on('error', console.error);
setTimeout(function(){ return callback();}, 100);
}
});
}
});
}
async.forEach(context.recommendations, likeRecommendation, function (error) {
if (!error) return done(null);
done(new Error('Could not like recommendations'));
});
}
The setTimeout will have to be placed at the end of the callback code.
Here is a possible solution (note that it doesn't use async.forEach)
var likeRecommendation = function (recommendation, callback) {
context.Client.like(recommendation._id, function (error, data) {
recommendation['drupal_user_uid'] = context.message.uid;
recommendation['drupal_user_uuid'] = context.message.uuid;
console.log(recommendation);
if (error) return done(new Error('Could not like recommendations'));
context.broker.publish('saves_swipes_publication', recommendation, function (err, publication) {
if (err) throw err
publication.on('error', console.error);
});
console.log('Liked!');
return callback()
});
}
function iterateWithTimeout(list, ctx, timeoutDuration) {
var currentIndex = 0;
(function invoke() {
list[currentIndex](ctx, function(error) {
if (!error) return done(null);
done(new Error('Could not like recommendations'));
setTimeout(function() {
if (++currentIndex < list.length) {
invoke();
}
}, timeoutDuration);
});
})();
}
// Interval is 1 second for now
iterateWithTimeout(context.recommendations, likeRecommendation, 1000);
So using "async.eachSeries" rather than "async.forEach" was the solution!
As always thanks for the help!

Connection.query to execute

Pretty sure this is a quite noobish node.js/callback question but I can't seem to find the proper code to make it run.
This is how I invoke my node-mysql code:
var utils = require('../../config/database/utils');
exports.getResults = function(callback) {
var query = "SELECT * FROM my_table";
utils.exec(query, null, function(err, results){
if(err){
console.log(err);
callback(true);
return;
}
console.log(results);
callback(false, results);
});
};
Next is the utils file where I can't get the code work.
var pool = require('./connection');
module.exports = {
getDBConnection: function() {
pool.getConnection(function(err, connection){
if(err){
console.log(err);
return;
}
return connection;
});
},
endDBConnection: function(connection) {
connection.end(function (err) {
if(err) {
console.log(err);
callback(true);
return;
}
});
},
exec: function(query, data, callback) {
console.log(query);
this.getDBConnection(function(err, connection){
if(err){
console.log('error');
}
console.log(connection);
connection.query(query, data, function(err, results) {
if(err) {
callback(err);
}
callback(false, results);
});
this.endDBConnection(connection);
});
}
}
Code is getting OK the the exec part since the console.log(query) logs the query. But after that, the code's not running, console.log(connection); doesn't show a thing, and of course the connection.query is also not running.
I'm not sure why this is happening.
Returning a value inside a callback is meaningless. You need to pass in a callback that gets called with the value you want to return:
getDBConnection: function(callback) {
pool.getConnection(function(err, connection){
if(err){
console.log(err);
return callback(err);
}
callback(null, connection);
});
},
You should also use connection.release() instead of connection.end() since you are using a pool:
endDBConnection: function(connection) {
connection.release();
},
In exec(), you have the wrong this. It should instead be something like:
exec: function(query, data, callback) {
console.log(query);
var self = this;
this.getDBConnection(function(err, connection){
if(err){
console.log('error');
return callback(err);
}
console.log(connection);
connection.query(query, data, function(err, results) {
self.endDBConnection(connection);
if(err) {
return callback(err);
}
callback(null, results);
});
});
}

Return from callback function in Javascript

How do I get the return value from inside a value of node.js/javascript callback?
function get_logs(){
User_Log.findOne({userId:req.user._id}, function(err, userlogs){
if(err) throw err;
if(userlogs){
// logs = userlogs.logs;
return "hello there is a logs";
} else {
return "there is no logs yet..."
}
})
}
var logs = get_logs();
console.log(logs);
You can't return the result from a function whose execution is asynchronous.
The simplest solution is to pass a callback :
function get_logs(cb){
User_Log.findOne({userId:req.user._id}, function(err, userlogs){
if(err) throw err;
if(userlogs){
// logs = userlogs.logs;
cb("hello there is a logs");
} else {
cb("there is no logs yet...)"
}
})
}
get_logs(function(logs){
console.log(logs);
});
You can't. You should instead pass another callback to your function. Something like this:
function get_logs(callback){
User_Log.findOne({userId:req.user._id}, function(err, userlogs){
if(err) throw err;
if(userlogs){
callback("hello there is a logs");
} else {
callback("there is no logs yet...");
}
})
}
get_logs(function(arg1) {
console.log(arg1);
});
function get_logs(callback) {
User_Log.findOne({
userId: req.user._id
}, function (err, userlogs) {
if (err) throw err;
if (userlogs) {
// logs = userlogs.logs;
callback("hello there is a logs");
} else {
callback("there is no logs yet...");
}
})
}
get_logs(function (data) {
console.log(data);
});
Uses callbacks...
In node.js almost all the callbacks run after the function returns , so you can do something like this
function get_logs(){
User_Log.findOne({userId:req.user._id}, function(err, userlogs){
if(err) throw err;
if(userlogs){
// logs = userlogs.logs;
do_something(logs)
} else {
console.log('No logs')
}
})
}

Categories

Resources