Best way to debug promises running in parallel - javascript

Am developing backend of an app using nodejs+express and using RSVP for promises.
Problem : whenever there is an error or exception in one of the functions that is unexpected the execution is stuck. Is there any way i can find which one of the functions have the error.
The code looks like this :
function checkifvalid_call() {
return new RSVP.Promise(function(fulfil, reject) {
common.checkifvalid(test, function(isValid) {
if (isValid === false) {
logger.fatal("Not valid test....sending invalid result")
res.send({
"Error": "Invalid test"
});
}
});
});
}
function secondtest_call() {
return new RSVP.Promise(function(fulfil, reject) {
common.secondtest(test, function(isValid) {
if (isValid === false) {
logger.fatal("Not valid second test....sending invalid result")
res.send({
"Error": "Invalid second test"
});
}
});
});
}
RSVP.allSettled([checkifvalid_call(), secondtest_call()]).then(function(ret_array) {
console.log("Calls finished");
logger.debug("sending result..............")
res.send("success);
}).catch(function(reason) {
logger.debug("Exception encountered : " + reason);
}).finally(function() {
logger.debug("All done finally")
});
RSVP.on('error', function(reason) {
console.assert(false, reason);
});
Thank you.

Try using try{}catch, and use RSVP's error handler on each of the promises instead of the entire thing. The current set of handlers only checks if 'allSettled' has an error afaik.
This blog post explains promises very well:
How To Use Promises

Related

React Native DRY Javascript

1) I have a specific implementation where I want to adhere to the DRY principles.
The structure of both the methods is almost exactly the same. I am wondering if this is a way not to repeat the implementation:
addCardToExistingCustomer(cardDetail){
PaymentUtil.stripeCreateCardToken(cardDetail).then((cardTokenResult)=>{
if(cardTokenResult.error){
console.log("There was an error with the card!");
} else {
PaymentUtil.addCardToExistingCustomer(cardTokenResult.id).then((card) =>{
});
}
});
}
addCardToNewCustomer(cardDetail){
this.stripeCreateCardToken(cardDetail).then((cardTokenResult)=>{
if(cardTokenResult.error){
console.log("There was an error with the card!");
} else {
console.log("Successfully created card token");
PaymentUtil.stripeCreateCustomer(cardTokenResult.id)
}
});
}
2) Is this the best way to chain promises ? Specifically how should you handle exceptions from the promises in the chain which aren't the last element of the chain.
Say for example promise getStripeCustomerId rejected. How should you handle the the rejection.
addCardToExistingCustomer(cardTokenResultId){
return this.getStripeCustomerId(userDetail).then((customerId) => {
return this.removeAllExistingCards(userDetail).then(()=>{
return Stripe.addCardToCustomer(cardTokenResultId,customerId);
});
});
},
getStripeCustomerId(userDetail){
return FirebaseRESTUtil.getStripeCustomer(userDetail.username)
.then((fbStripe) => (fbStripe.customerId));
},
1- This way can be better.. It will use promises chains to work on data.
getCardTokenResult(cardDetail) {
return PaymentUtil.stripeCreateCardToken(cardDetail)
.then((cardTokenResult) => {
if(cardTokenResult.error){
return Promise.reject('There was an error with the card!!');
} else {
return cardTokenResult;
}
})
.catch((error) => console.log(error)):
}
addCardToExistingCustomer(cardDetail){
return getCardTokenResult(cardDetail)
.then((cardTokenResult) => {
PaymentUtil.addCardToExistingCustomer(cardTokenResult.id).then((card) =>{
// do something
});
});
}
addCardToNewCustomer(cardDetail){
return getCardTokenResult(cardDetail)
.then((cardTokenResult) => {
PaymentUtil.stripeCreateCustomer(cardTokenResult.id);
});
}
2- You can use catch to get errors on Promises chain. You can look the code above. I added catch to get cardtokenresult error. You can continue same way on chain to get other errors.
I noticed that you're checking for errors in the first argument of your then. I'm pretty sure this is incorrect as Stripe does not return HTTP 200 status on errors.
Having said that, I like to flatten chained promises instead of nesting them because I find that it makes the code easier to maintain and read:
addCardToExistingCustomer(cardTokenResultId) {
return this.getStripeCustomerId(userDetail).then((customerId) => {
return this.removeAllExistingCards(userDetail); // returns a promise
}).then(() => {
return Stripe.addCardToCustomer(cardTokenResultId,customerId); // returns a promise
});
},
Now any errors will bubble up to the main outer promise, so you can check for errors by
addCardToExistingCustomer(myId).then(() => {
console.log('success!');
}, (error) => {
console.log(error);
});

How to proper chain promises calls that depend on one another?

I have the following code:
const request = require('request-promise');
request(validateEmailOptions).then(function(result) {
if (result.valid) {
request(createUserOptions).then(function (response) {
if (response.updatePassword) {
request(modifyUserOptions).then(function (response) {
return res.redirect('/signin');
}).catch(function(error) {
return res.redirect('/error');
});
}
}).catch(function(error) {
return res.redirect('/error');
});
} else {
return res.redirect('/error');
}
})
.catch(function (reason) {
return res.redirect('/error');
});
Basically, it's a chain of request call, each one based on the result of the previous call. The problem is that I have many more lines in each condition and as a result, my code is bloated and hard to read and follow. I want to know if there is a better way to write the call chain using request-promises or simply request and bluebird.
You can unnest the promises. Think that this:
f(a).then(function(a) {
return g(b).then(function(b) {
return h(c)
})
})
Is the same as:
f(a).then(function(a) {
return g(b)
}).then(function(b) {
return h(c)
})
I would recommend failing as early as possible, that means handling the error condition first, and having meaningful error messages to be able to log them if need be. Finally, you can propagate the error and handle it in a single catch. To put it in context in your code:
request(validateEmailOptions).then(function(result) {
if (!result.valid) {
throw new Error('Result is not valid');
}
return request(createUserOptions);
}).then(function(response) {
if (!response.updatePassword) {
throw new Error('Password is not updated');
}
return request(modifyUserOptions);
}).then(function(response) {
return res.redirect('/signin');
}).catch(function(error) {
// you may want to log the error here
return res.redirect('/error');
});

Trapping AssertionError in nested callback function

I am writing an updated testing library for Node.js and am trying to properly trap errors that occur in test callbacks
for some reason, the following code doesn't trap an AssertionError:
process.on('uncaughtException',function(err){
console.error(err); //an instance of AssertionError will show up here
});
[file1,file2,file2].forEach(function (file) {
self.it('[test] ' + path.basename(file), {
parallel:true
},function testCallback(done) {
var jsonDataForEnrichment = require(file);
request({
url: serverEndpoint,
json: true,
body: jsonDataForEnrichment,
method: 'POST'
}, function (error, response, body) {
if (error) {
done(error);
}
else {
assert(response.statusCode == 201, "Error: Response Code"); //this throws an error, which is OK of course
done();
}
});
});
});
I handle the callback (I named it "testCallback" above), with this code:
try {
if (!inDebugMode) {
var err = new Error('timed out - ' + test.cb);
var timer = setTimeout(function () {
test.timedOut = true;
cb(err);
}, 5000);
}
test.cb.apply({
data: test.data,
desc: test.desc,
testId: test.testId
}, [function (err) { //this anonymous function is passed as the done functon
cb(err);
}]);
}
catch (err) { //assertion error is not caught here
console.log(err.stack);
cb(err);
}
I assume the problem is that callbacks that result from async functions like those made in the request module, cannot be trapped by simple error handling.
What is the best way to trap that error?
Should I just flesh out the process.on('uncaughtException') handler? Or is there a better way?
The best way to handle this appears to be Node.js domains, a core module
https://nodejs.org/api/domain.html
it will likely be deprecated soon, but hopefully there will be a replacement that can have similar functionality, because the domain module is saving my ass right now, as I have no other way to trap errors, because the errors might be generated by my users' code, not my code.

Expects aren't working in Chai as Promised results

I'm new to Promises in JavaScript, and whilst it seems to be working for me to an extent, I'm unable to test the 'reject' value.
I'm passing through an Error, and want to ensure that it is an error and more importantly, that the error code matches what I'm expecting.
return new Promise(function(resolve, reject){
tableService.deleteEntity(config.azureTable.tableName,
visitor.azureEntity(), function (error, response) {
// If successful, go on.
if (!error) {
resolve(response);
}
// If unsuccessful, log error.
else {
/* If we know it's a resourceNotFound
that's causing the error, return that. */
if (error.code === 'ResourceNotFound') {
reject(new Error('Record not found'));
}
// For unexpected errros.
else {
reject(new Error('Table service error (delete): ' + error));
}
}
});
});
The test, in Mocha - using chai and chai-as-promised. Everything else is working (I have 24 passing tests) - but this one has me stuck!
it('return an error when the lookup fails', function (done) {
storage.delete(globalUUID).then(function(sucess) {
done(sucess);
}, function(error) {
expect(error).to.be.an(Error);
done();
});
});
Any help would be greatly appreciated.
You are not using chai-as-promised anywhere. If your first code example is the body of the storage.delete method, then your test should look like:
it('return an error when the lookup fails', function() {
expect(storage.delete(globalUUID)).to.be.rejectedWith(Error);
});

How to bubble error correctly from Promise without throw?

I have the following TypeScript method which returns a promise:
public loadSavedLogin(): ng.IPromise<MyApp.Models.User> {
return this._myAppService.getUser(this.savedUserId).then((result: MyApp.Models.User) => {
if (result) {
this.userId = result.UserID;
this.userName = result.UserName;
}
return result;
}, (error) => {
this._isAuthError = true;
return error;
}
);
}
The problem I have is in the promise's error callback. The upstream calls to this method also rely on a promise so if the error does not bubble up correctly, the upstream promise doesn't function correctly. I found a hackish solution:
(error) => {
try {
this._isAuthError = true;
return error;
} catch (e) {
//If any error occurred above make sure to still throw
throw error;
} finally {
//Allow upstream promises to continue as expected
throw error;
}
}
This works but looks, feels, and is probably all wrong. I feel like I'm missing a proper implementation when handling and bubbling errors in a promise. There has to be a more proper/correct way of handling the error function in this promise as I've done, and yet still allow upstream promise's making a call to this method to work properly as well when handling their own error function.
How do I get the error to bubble without the series of hackish throw statements?
Note: It seems redundant to return the error and throw as well, but the IPromise interface I'm using will not compile if I don't return a value. This is why I return and throw the error.
Note: I read a ton of the questions on handling errors with promises, but none of them are answering the question as I'm asking in regards to preventing the hackish approach I've taken.
I am not conversant with TypeScript, but here is a javascript solution, where you use $q.reject
.then(function() {},
function(error) {
this._isAuthError = true;
return $q.reject(error);
});`
Just throw the error instead of ever returning it:
public loadSavedLogin(): ng.IPromise<MyApp.Models.User> {
return this._myAppService.getUser(this.savedUserId).then((result: MyApp.Models.User) => {
if (result) {
this.userId = result.UserID;
this.userName = result.UserName;
}
return result;
}, (error) => {
this._isAuthError = true;
throw error;
}
);
}
Note that a valid return (i.e. not returning a promise / rejected promise) from a rejection handler makes the next promise in the chain fulfilled.

Categories