I want async parallel not to break on error - asynchronous

I'm using caolan/async specifically .parallel() and I'm assembling an object of strings. When there's an error the whole thing exists and doesn't finish, even the processes without errors.
async.parallel({
"color": color,
"brand": brand,
"sku": sku,
}, function(err, result) {
console.log(err);
console.log(result);
});
If brand returns an error, I don't get any information. I'd rather brand:false. How can I achieve this?

async.parallelPlus = function(functions, callback) {
var wrap = function(func) {
return function(callback) {
func(function(err, value) {
if (err) return callback(null, false);
return callback(null, value);
});
}
}
var newFunctions = {};
for (var func in functions) {
newFunctions[func] = wrap(functions[func]);
}
return async.parallel(newFunctions, callback);
}

Related

AWS Lambda Nodejs async.waterfall not executing MQTT Function

I am trying to use async.waterfall in the exports handler, and call functions sequentially. One of the function is related to MQTT message publishing. While the functions are being called, but when the MQTT function gets called, it just stops and not calls the require ('MQTT').
exports.handler = function(event, context) {
var async = require('async');
async.waterfall([
function(callback) {
retrieveEmailId(apiAccessToken,callback)
},
function(emailId, callback) {
retrieveDeviceDetails(callback)
},
function(deviceDetail, callback) {
publishMsg(callback)
}
], function(err, result) {
if (err) console.log('Error :: \n' + err);
});
}
function retrieveEmailId(accessToken, callback) {
var getEmailFromAlexaProfileObj = require('./GetEmailFromAlexaProfile');
getEmailFromAlexaProfileObj.doIt(accessToken, function(returnVal) {
console.log(returnVal);
callback(null, returnVal)
});
}
function retrieveDeviceDetails(callback) {
var getDevcieDetailsObj = require('./GetDevcieDetails');
getDeviceDetailsObj.doIt(null, function(returnVal) {
console.log(returnVal);
callback(null, returnVal)
});
}
function publishMsg() {
var mqtt = require('mqtt');
var options = {
clientId: "xxx",
username: "yyy",
password: "zzz",
clean: true
};
var client = mqtt.connect("mqtt://xxx.com", options)
client.on("connect", function () {
client.publish('xxx/yyy/L1', "1", options);
client.end();
});
}
Have you tried running the code locally using "lambda-local"? Does that sequence of call work along with the last one that is MQTT? What have you noticed when you invoke "require('mqtt')" within lambda?
Problem got resolved if the require variable is done prior to exports.handler.
for example....
var AWS = require('aws-sdk');
var async = require('async');
exports.handler = function(event, context) {
....
}

Correct way to fan out data in Firebase Queue

I want to fan out data to 4 different nodes.
Since firebase transaction process can be failed, what is the right approach to ensure that all 4 data will be saved?
Suppose that I have 4 functions for saving data, each will call a transaction.
Edit:
function saveToFirstNode(data, response) {
/*
* #param
* [response] is a callback function
* that indicates whether the save was successful
*/
firebase.database().ref('cars/' + data.carId)
.transaction(function(currentData) {
currentData.distance += data.distance;
return currentData;
}, function(error, commited, snapshot) {
if (error) {
response(false);
} else if (commited) {
response(true)
}
}, false);
}
function saveToSecondNode(data, response) {...}
function saveToThirdNode(data, response) {...}
function saveToFourthNode(data, response) {...}
1. Using the first approach
This approach uses nested callback function and calls progress() for every success in saving.
The downside is, if one of the saving process fails, it will re-save all data from the first to fourth.
var queue = new Queue(ref, options, function(data, progress, resolve, reject) {
saveToFirstNode(data, function(success) {
if (success) {
progress(25);
saveToSecondNode(data, function(success) {
if (success) {
progress(50);
saveToThirdNode(data, function(success) {
if (success) {
progress(75);
saveToFourthNode(data, function(success) {
if(success) {
resolve(data);
} else {
reject();
}
});
} else {
reject();
}
});
} else {
reject();
}
});
} else {
reject();
}
});
});
2. Using the second approach
This approach guarantee all data will be saved. When the saving process fails, it will retry from the failed specs, not from the first to fourth. But do you think it is an overkill just for doing 4 save? Is this the right approach?
Define specs in queue/specs:
{
"save_to_first_node": {
"in_progress_state": "save_to_first_node_in_progress",
"finished_state": "save_to_first_node_finished"
},
"save_to_second_node": {
"start_state": "save_to_first_node_finished",
"in_progress_state": "save_to_second_node_in_progress",
"finished_state": "save_to_second_node_finished"
},
"save_to_third_node": {
"start_state": "save_to_second_node_finished",
"in_progress_state": "save_to_third_node_in_progress",
"finished_state": "save_to_third_node_finished"
},
"save_to_fourth_node": {
"start_state": "save_to_third_node_finished",
"in_progress_state": "save_to_fourth_node_in_progress"
}
}
Queue code:
var saveToFirstNodeOptions = {'specId': 'save_to_first_node'};
var saveToFirstNodeQueue = new Queue(ref, saveToFirstNodeOptions, function(data, progress, resolve, reject) {
saveToFirstNode(data, function(success) {
if (success) resolve(data);
else reject();
});
});
var saveToSecondNodeOptions = {'specId': 'save_to_second_node'};
var saveToSecondNodeQueue = new Queue(ref, saveToSecondNodeOptions, function(data, progress, resolve, reject) {
saveToSecondNode(data, function(success) {
if (success) resolve(data);
else reject();
});
});
var saveToThirdNodeOptions = {'specId': 'save_to_third_node'};
var saveToThirdNodeQueue = new Queue(ref, saveToThirdNodeOptions, function(data, progress, resolve, reject) {
saveToThirdNode(data, function(success) {
if (success) resolve(data);
else reject();
});
});
var saveToFourthNodeOptions = {'specId': 'save_to_fourth_node'};
var saveToFourthNodeQueue = new Queue(ref, saveToFourthNodeOptions, function(data, progress, resolve, reject) {
saveToFourthNode(data, function(success) {
if (success) resolve(data);
else reject();
});
});
Which is the right approach? This question is not preference, as those two are completely difference approach and make huge impact on both performance and effectiveness.

how to push data back to client in meteor?

I have to make a aggregate query to DB when the user click on a button, however I don't know how to return that result back to the client since I'm doing an asynchronous request, this is part of my code:
//Server side
Meteor.startup(function() {
Meteor.methods({
getAllTotals: function (query){
var db = MongoInternals.defaultRemoteCollectionDriver().mongo.db;
var error = result = match = pipeline = '';
var group = {
$group: {
_id: null,
wall_clock: {
"$sum": "$wall_clock"
},
mem:{
"$sum": "$mem"
},
cpu:{
"$sum": "$cpu"
},
io:{
"$sum": "$io"
},
vmem:{
"$sum": "$vmem"
},
maxvmem:{
"$sum": "maxvmem"
}
}
};
if(typeof query.submission_time !== "undefined"){
match = {"$match": {submission_time: query.submission_time}};
pipeline = [match, group];
}else{
pipeline = [group];
}
db.collection("GE_qstat_job_monitor").aggregate(
pipeline,
Meteor.bindEnvironment(
function (error, result){
console.log(result); // <<--- this is OK!
},
function(error) {
Meteor._debug( "Error doing aggregation: " + error);
}
)
);
return result; // <<--- this is empty
}
});
}
any suggestion? :-)
Short answer:
Solution you can find here:
How to get an async data in a function with Meteor
Detailed answer
using Meteor._wrapAsync
var aggregateTotal = function(callback){
var db = MongoInternals.defaultRemoteCollectionDriver().mongo.db;
// ...
db.collection("GE_qstat_job_monitor").aggregate(
pipeline,
function (error, result){
if(error){
callback(error);
}else{
callback(null, result);
}
}
);
}
var aggregateTotalsSync = Meteor._wrapAsync(aggregateTotal);
Meteor.methods({
'getAllTotals': function(){
var result;
try{
result = aggregateTotalsSync();
}catch(e){
console.log("getAllTotals method returned error : " + e);
}finally{
return result;
}
}
});
using Futures (meteorPad example)
//Server side
Meteor.startup(function() {
var Future = Npm.require('fibers/future');
Meteor.methods({
getAllTotals: function (query){
var fut = new Future();
var db = MongoInternals.defaultRemoteCollectionDriver().mongo.db;
// ...
db.collection("GE_qstat_job_monitor").aggregate(
pipeline,
Meteor.bindEnvironment(
function (error, result){
if(error){
fut.throw(error);
}else{
fut.return(result)
}
},
function (exception){
// caught exception is passed to this callback
fut.throw(exception);
}
)
);
return fut.wait();
}
});
}
Easy but a bit dirty way (but not so much if you think well about your architecture) -> send back the result trough Mongo.
You can even do it without Meteor.methods, with the request creation inserted in the database on the client, an observer on the server that check it and does the async task, and then write back the result in the database.

Cannot call method 'create' of undefined

Here is what I'm getting from the console server side.
I20140516-21:27:12.142(0)? There was an error on this page. Cannot call method 'create' of undefined
I am not finding a good reason why this method isn't defined. I have the balanced-payments-production package from Atmosphere loaded and this includes the balanced.js file and the api export to the server. Any help here is appreciated.
Here is my events.js file
Template.CheckFormSubmit.events({
'submit form': function (e, tmpl) {
e.preventDefault();
var recurringStatus = $(e.target).find('[name=is_recurring]').is(':checked');
var checkForm = {
name: $(e.target).find('[name=name]').val(),
account_number: $(e.target).find('[name=account_number]').val(),
routing_number: $(e.target).find('[name=routing_number]').val(),
recurring: { is_recurring: recurringStatus },
created_at: new Date
}
checkForm._id = Donations.insert(checkForm);
Meteor.call("addCustomer", checkForm, function(error, result) {
console.log(error);
console.log(result);
// Successful tokenization
if(result.status_code === 201 && result.href) {
// Send to your backend
jQuery.post(responseTarget, {
uri: result.href
}, function(r) {
// Check your backend result
if(r.status === 201) {
// Your successful logic here from backend
} else {
// Your failure logic here from backend
}
});
} else {
// Failed to tokenize, your error logic here
}
// Debuging, just displays the tokenization result in a pretty div
$('#response .panel-body pre').html(JSON.stringify(result, false, 4));
$('#response').slideDown(300);
});
var form = tmpl.find('form');
//form.reset();
//Will need to add route to receipt page here.
//Something like this maybe - Router.go('receiptPage', checkForm);
},
'click [name=is_recurring]': function (e, tmpl) {
var id = this._id;
console.log($id);
var isRecuring = tmpl.find('input').checked;
Donations.update({_id: id}, {
$set: { 'recurring.is_recurring': true }
});
}
});
Here is my Methods.js file
function getCustomer(req, callback) {
try {
balanced.marketplace.customers.create(req, callback);
console.log(req.links.customers.bank_accounts);
}
catch (error){
var error = "There was an error on this page. " + error.message;
console.log(error);
}
}
var wrappedGetCustomer = Meteor._wrapAsync(getCustomer);
Meteor.methods({
addCustomer: function(formData) {
try {
console.log(formData);
return wrappedGetCustomer(formData);
}
catch (error) {
var error = "There was an error on this page." + error.message;
console.log(error);
}
}
});
I needed to run balanced.configure('APIKEYHERE'); first, then run the balanced code.

return values from server side meteor methods

Here is my code,
googleContacts:function()
{
var opts= { email: Meteor.user().services.google.email,
consumerKey: "xxxxxxxx",
consumerSecret: "xxxxxxxxxx",
token: Meteor.user().services.google.accessToken,
refreshToken: Meteor.user().services.google.refreshToken};
gcontacts = new GoogleContacts(opts);
gcontacts.refreshAccessToken(opts.refreshToken, function (err, accessToken)
{
if(err)
{
console.log ('gcontact.refreshToken, ', err);
return false;
}
else
{
console.log ('gcontact.access token success!');
gcontacts.token = accessToken;
gcontacts.getContacts(function(err, contact)
{
console.log(contact);
return contact;//want to return this value
})
}
});
}
I want to return the contact to the called method,as it is in a inner function i'm getting a bit difficult to return it to the called method.If it is in client side,then we can store the value in a session variable and we can return that,but this is a server side method,How to do this?
Use Futures:
Future = Npm.require('fibers/future');
Meteor.methods({
methodname: function() {
var fut = new Future();
apiCall(function(err, res) {
fut.return(...);
});
return fut.wait();
},
});

Resources