setTimeout inside a callback failed to remove a mongodb document [duplicate] - javascript

I am using stripe for payments in my app, I want to create a receipt document in my own database after a succesful transaction
My code:
Meteor.methods({
makePurchase: function(tabId, token) {
check(tabId, String);
tab = Tabs.findOne(tabId);
Stripe.charges.create({
amount: tab.price,
currency: "USD",
card: token.id
}, function (error, result) {
console.log(result);
if (error) {
console.log('makePurchaseError: ' + error);
return error;
}
Purchases.insert({
sellerId: tab.userId,
tabId: tab._id,
price: tab.price
}, function(error, result) {
if (error) {
console.log('InsertionError: ' + error);
return error;
}
});
});
}
});
However this code returns an error:
Error: Meteor code must always run within a Fiber. Try wrapping callbacks that you pass to non-Meteor libraries with Meteor.bindEnvironment.
I am not familiar with Fibers, any idea as to why this is?

The problem here is that the callback function which you pass to Stripe.charges.create is called asynchronously (of course), so it's happening outside the current Meteor's Fiber.
One way to fix that is to create your own Fiber, but the easiest thing you can do is to wrap the callback with Meteor.bindEnvironment, so basically
Stripe.charges.create({
// ...
}, Meteor.bindEnvironment(function (error, result) {
// ...
}));
Edit
As suggested in the other answer, another and probably better pattern to follow here is using Meteor.wrapAsync helper method (see docs), which basically allows you to turn any asynchronous method into a function that is fiber aware and can be used synchronously.
In your specific case an equivalent solution would be to write:
let result;
try {
result = Meteor.wrapAsync(Stripe.charges.create, Stripe.charges)({ /* ... */ });
} catch(error) {
// ...
}
Please note the second argument passed to Meteor.wrapAsync. It is there to make sure that the original Stripe.charges.create will receive the proper this context, just in case it's needed.

You might want to take a look at the docs for http://docs.meteor.com/#/full/meteor_wrapasync.

Related

aws-sdk-js E2 createVPC is executed twice while waiting adding a promise

ec2
.createVpc(params, function (err, data) {
if (err) {
console.log(err, err.stack);
// an error occurred
} else {
logger.log.info(
`Deployment VPC ${deployment.name} has been created.`
);
db.saveData(data, deployment.name);
return data;
}
})
.promise()
I was trying to run this code above, which is the most simplest resource in the docs. But when I added .promise() the create operation was triggered twice. When I remove it, it creates only one instance of VPC. But I need to access the information about the created resource in order to save it to the database.
I would guess that this happens because you mix two ways of triggering a request - providing a callback and calling a promise. If you want to use promises, you should process the returned data in then() (or use await).
Example with then():
ec2.createVpc(params).promise().then((data) => {
logger.log.info(
`Deployment VPC ${deployment.name} has been created.`
);
db.saveData(data, deployment.name);
return data;
}, (err) => {
console.log(err, err.stack);
})

node.js : How do I pass in multiple variables into a view?

I'm trying to create a webpage where there is an instance of all the current Projects I am working on, on the left, so I'd need a .forEach() function in order to loop through all of them in order to display it, but on the other side, I need to display the information that is currently selected.
Please first take a look at my code block so I can try to explain the thought process behind what I was trying to do.
So I didn't have any problems selecting the information of the single project that I needed to display on this webpage. I used the .findOne() function in order to pick out the information that I needed.
The problem that I'm facing is that I also need to pass a var that's connected to the .find() function in order to pass through all of the elements of the database. The way I went about this is that I thought I would be able to set the definition of allProjects by manually running the .find() function, and then returning it, thus assigning Projects.find() to allProjects.
app.get('/projects/:url', (req, res) => {
Projects.findOne({ Url: req.params.url }, (err, foundProject) => {
if (err) {
console.log(err);
} else {
res.render('show', {
foundProject: foundProject,
allProjects: Projects.find({}, (err, allProjects) => {
if (err) {
res.send('error');
} else {
return allProjects;
}
})
});
}
});
});
I thought that by returning allProjects and then also having that assigned to allProjects, i'd be able to use the allProjects variable in my show.ejs page.
Unfortunately, I'm getting an error 'allProjects.forEach() is undefined' which leads me to believe that in the app.js where I am defining allProjects, it's not being assigned the correct value that I want it assigned.
It looks like you're expecting return allProjects to do something, but that's actually ignored. Unless you have a callback function you can call, that will go into the void and never be seen by anyone. This is true of virtually all callback functions. They do not care what value that function returns because it's never relevant, what they want is the future value which comes through the callback given to this function.
In other words it plays out like this:
asyncFunctionTakingCallback(function(cb) {
cb(null, value); // This is the important value!
return value; // Nobody cares about this value. Don't even bother.
});
To fix that you need to move the render call inside of the inner-most callback function:
app.get('/projects/:url', (req, res) => {
Projects.findOne({ Url: req.params.url }, (err, foundProject) => {
if (err) {
console.log(err);
// Return here to avoid another level of indentation below
return;
}
Projects.find({}, (err, allProjects) => {
if (err) {
res.send('error');
} else {
res.render('show', {
foundProject: foundProject,
allProjects:
});
}
});
});
});
Now that's still a dizzying amount of code and the nesting here is getting completely out of control even though this is relatively simple Node code.
For comparison here's a version that uses async functions:
app.get('/projects/:url', async (req, res) => {
let foundProject = await Projects.findOne({ Url: req.params.url });
res.render('show', {
foundProject: foundProject,
allProjects: await Projects.find({})
});
});
There's really not much to it this way. What await does is basically stall out on that line and wait for the promise to get resolved or produce an error. Any errors produced should be captured with try { ... } catch as usual.

Return value from callback function in AWS Javascript SDK

I'm using the AWS Javascript SDK and I'm following the tutorial on how to send an SQS message. I'm basically following the AWS tutorial which has an example of the sendMessage as follows:
sqs.sendMessage(params, function(err, data) {
if (err) {
console.log("Error", err);
} else {
console.log("Success", data.MessageId);
}
});
So the sendMessage function uses a callback function to output whether the operation was successful or not. Instead of printing to the console I want to return a variable, but every value I set is only visible within the callback function, even global variables like window.result are not visible outside the callback function. Is there any way to return values outside the callback?
The only workaround I've found at the moment is to set a data attribute in an HTML element, but I don't think it's really elegant solution.
I would suggest to use Promises and the new async and await keywords in ES2016. It makes your code so much easier to read.
async function sendMessage(message) {
return new Promise((resolve, reject) => {
// TODO be sure SQS client is initialized
// TODO set your params correctly
const params = {
payload : message
};
sqs.sendMessage(params, (err, data) => {
if (err) {
console.log("Error when calling SQS");
console.log(err, err.stack); // an error occurred
reject(err);
} else {
resolve(data);
}
});
});
}
// calling the above and getting the result is now as simple as :
const result = await sendMessage("Hello World");

Javascript return is not returning anything

I have a NodeJS server and a helper function that is making a HTTP request, but when I make the call for the function, it comes up as undefined. The call is being made in a callback, so I don't think that there is a problem with the Async part of it.
This is the server.js
console.log(dictionary('wut'));
And this is the function dictionary.
if(dictionary[word]===undefined){
request({
url:"https://mashape-community-urban-dictionary.p.mashape.com/define?term="+word,
headers:{
'X-Mashape-Key':'KEY HERE',
'Accept':'text/plain'
}
}, function(err, response, body){
if(!err && response.statusCode==200){
var info = JSON.parse(body);
console.log(info.list[0].definition);
return info.list[0].definition;
}
});
} else {
return dictionary[word];
}
Where word is the word that is being passed to the function.
Edit: I forgot to mention that the dictionary function has
module.exports = function(word){
The return statements are supposed to give the module the value from the callback. Sorry about that, that's kind-of important information.
You're going to want to use a callback method with your helper method.
So your helper defintion would look like this:
function dictionary(word, callback) {
request({}, function(err, res, body) {
if (err) {
return callback(err);
}
callback(null, body);
});
}
And your call would become:
dictionary('wut', function(err, result) {
if (err) {
return console.error('Something went wrong!');
}
console.log(result);
});
This is obviously a very simple implementation, but the concept is there. Your helpers/ modules/ whatever should be written to accept callback methods that you can then use to bubble up errors and handle them in the appropriate place in your application. This is pretty much the standard way to do things in Node.
Here is how you could call your helper using a simple Express route:
router.route('/:term')
.get(function(req, res) {
dictionary(req.params.term, function(err, result) {
if (err) {
return res.status(404).send('Something went wrong!');
}
res.send(result);
});
});
From my viewpoint, it looks like that request library you're using was designed asynchronous. This means that you should handle the data inside of the callback function.
For instance:
function handle(data) {
// Handle data
console.log(data)
}
if(dictionary[word]===undefined){
request({
url:"https://mashape-community-urban-dictionary.p.mashape.com/define?term="+word,
headers:{
'X-Mashape-Key':'KEY HERE',
'Accept':'text/plain'
}
}, function(err, response, body){
if(!err && response.statusCode==200){
var info = JSON.parse(body);
console.log(info.list[0].definition);
handle(info.list[0].definition)
}
});
} else {
handle( dictionary[word] )
}
You didn't provide enough information for me to set this up correctly. But hopefully this gives you an idea on what you need to do.
To elaborate on why you should set it up this way:
The request function appears to be asynchronous, so keep it how it was designed.
You're returning inside of the callback, so your outer dictionary function isn't getting that returned data, the callback is.
Since the request function was designed async, there isn't a way to return the data to the dictionary without forcing it to be synchronous (which isn't advised). So you should restructure it to be handled inside of the callback.
(Another little note, you should use typeof dictionary[word] === "undefined", because I believe JavaScript sometimes throws an error otherwise.)

Pattern for short circuiting async flows on non-errors in Node.js

Node uses the CPS convention for callbacks. Generally in the event a function returns an error the practice is to either handle the error or callback the error to your parent by doing something like return cb(err).
The issue I have is that often I need to short-circuit a pathway, but I don't actually have an "error" per-se. Is there an established pattern for doing this?
This issue comes up especially often when using async for flow control.
Here is an example:
var primaryFunction = function(arg1, cb) {
var template;
var data;
var result;
async.series([
function(cb) {
// load some data from different sources
async.parallel([
function(cb) {
fs.readFile("/somepath", function(err, temp) {
if (err) { return cb(err); }
template = temp;
cb(null);
});
},
function(cb) {
api.find({}, function(err, temp) {
if (err) { return cb(err); }
data = temp;
cb(null);
});
}
]
},
function(cb) {
// do a bunch more work
cb(null);
},
function(cb) {
// do a bunch more work
cb(null);
},
function(cb) {
// combine data and template
result = goatee.fill(template, data);
cb(null);
}
], function(err) {
if (err) { return cb(err); }
cb(null, result);
});
}
Lets imagine if the api returns no documents, then I want to halt the flow control so it doesn't run any of the rest of that big async chain, but it's not exactly an error. It's just a short circuit out so maybe I'll put a friendly message on the screen and save myself some processing cycles.
Here are some options I consider:
Pass a non-error such as cb("halt") and then check err instanceof Error in the final callback. The non-null value causes async to not run additional series. Then in my final callback I treat "real" errors one way (passing them up), and "my" errors my own way.
I could create my own Error type and then return that and err instanceof MyError in the final callback. The issue here I've heard creating errors is expensive (certainly more expensive than a string or plain old {}).
I could create a next style callback, but then the system does not play nicely with async and deviates from the CPS standard.
I could use promises, since they provide a double callback idea with a success callback and a fail callback, but I'm just not a fan or promises since they aren't as universal as node CPS and there are too many competing implementations.
I could set a variable to halt the state, but then I have to check that halt variable in every function in the asyn chain.
Right now, returning simple strings or simple objects seems the best, again this is for intra-module communications not communications that would ever reach outside my module. That solution "feels" dirty, but it technially works. Any ideas?
I would use option 2 myself. I'd create a HaltCondition error like so:
function HaltCondition(reason) {
Error.call(this);
this.message = reason;
}
util.inherits(HaltCondition, Error);
Then use that as the error parameter in the callback when I need to short circuit the rest of the async flow. I know you're concerned about the expense of creating an error object but, in my experience, it's negligible.
I threw together a quick test and profiled it to see what the difference would be between using the HaltCondition error and just returning true as the error instead (like your option 1).
This is the code I used (similar to the code in your question):
var async = require('async'),
util = require('util');
function HaltCondition(reason) {
Error.call(this);
this.message = reason;
}
util.inherits(HaltCondition, Error);
async.series([
function(cb) {
async.parallel([
function(cb) {
setTimeout(function() {
cb(null, 'a');
}, 10);
},
function(cb) {
setTimeout(function() {
cb(null, 'b');
}, 20);
},
], cb)
},
function(cb) {
setTimeout(function() {
cb(new HaltCondition("test halt"), 'd');
}, 50);
},
function(cb) {
setTimeout(function() {
cb(null, 'e');
}, 30);
}
], function(err, result) {
if (err instanceof HaltCondition) {
console.log('HALTED:', err.message);
} else if (err) {
console.log('ERROR:', err.message);
} else {
console.log('DONE:', result)
}
});
I'm halting the async flow in the second series function.
When I was testing it with simply using true, I replaced the following lines:
cb(new HaltCondition("test halt"), 'd'); with cb(true, 'd');
and:
if (err instanceof HaltCondition) { with if (err === true) {
I profiled it in node v0.10.30 using node --profile and then processed v8.log with node-tick.
When using HaltCondition the code executed in an average of 93.2 ticks over 100 runs
When using true the code executed in an average of 93.3 ticks over 100 runs
An average of 0.1 ticks difference over 100 runs is basically nonexistent (and easily within the margin of error anyway).

Categories