Firebase in node.js, set() callback is delayed - firebase

I have an EC2 instance running a small node script connecting to Firebase. Strangely enough, it happens quite often on a small instance that the set operation gets executed immeditely but the callback function only gets called much later (between 30s to 2 minutes). Do you see any reason why it would happen that way?
console.log('creating');
// Create workspace
rootRef.child('spaces').child(chid).set(req.space, function(error) {
var end = new Date().getTime();
var time = end - start;
console.log('- created', error, time);
});

The bug is directly related to node 0.11 (set() callback is only called the first name in my scenario). Just revert to 0.10.x and it's all fixed!

I've been facing the same issue. the "Set" callback is not being invoked at all. I noticed, however, that if I run a snippet code similar to yours in a standalone file, the callback is invoked very quickly.
It turned out that if you're installing listeners on the same Node you're calling the "set" function on (i.e., on('child_added'), on('child_removed') ... etc) and that Node has a huge number of records, it'll simply take ages.
I removed the listeners ( to test) and the "set" started to invoke the callback very quickly.
I hope this helps!

Related

meteor autorun responds slower than helper

i've been battling for a few days with an autorun function that renders elements on a canvas for two players in a board game. the whole process from when 1 player places a move until its visible for the other player took too long. i managed to cut alot by optimizing the code i have written as a meteor beginner, and also by placing the method that updates the game move inside a (meteor.isServer) so it won't first run the method in the move maker's client (it was already just inside the server's folder).
one delay in time which is beyond my understanding, happens from the moment the server finishes with the move making method until the client's autorun begin to run(about 60 ms delay for chrome, and 150(!) for firefox). i've ran some tests to try and narrow down the options for why it happens, the last one was to subscribe to the games collection from a different page, and see if the response time is slow there too. this is the code:
Template.Watch.onCreated(function(){
this.subscribe('activeGames');
this.autorun(()=>{
if(this.subscriptionsReady()){
console.log(Games.findOne().turn + " " + (new Date).getTime());
}
});
});
Template.Watch.helpers({
games: ()=> {
console.log(Games.findOne().turn + " " + (new Date).getTime());
return Games.find({result: false});
}
});
now, on the client both console.logs appeared whenever a move was played, the weird thing is that the helper's console.log was fired with no delay, 50 ms before the autorun's console.log which had the same delay as in the game page.
by my poor understanding, if the client knows a change was made to the database, the autorun should simply run, just like the helper simply runs.
i would be very grateful to whoever explains to me the behavior of the autorun that causes that delay, and if there is a way to cancel it.
Thanks in advance!
When you call a method on the client using Meteor.call, two things happen in parallel:
The client sends a request to the server to run the method in a secure
environment, just like an AJAX request would work A simulation of the
Method runs directly on the client to attempt to predict the outcome
of the server call using the available information.
So here is the reason why your Helper console print before the autorun.
Your mini-mongo(client side DB) get updated before the server data update according to point number 2.
According to point number 1, the client sends a request to the server, then server updates the server database. Server re-publish the data to the client and autorun reinitialize in your case.
So the point is your mini mongo(client side DB) updated before the subscription ready. that's why you got console log in helper before your autorun.
One more thing happen when your server data to client::
If the result from the server comes back and is consistent with the
simulation on the client, everything remains as is. If the result on
the server is different from the result of the simulation on the
client, the UI is patched to reflect the actual state of the server.

Iron router + observechanges = repeated observechanges handler calls?

I'm attempting to use observechanges with iron router but they don't seem to be compatible at all.
Router.route('/gaming', {
waitOn: function() {
return Meteor.subscribe('chat', function() {
window.chatmessagesCache = new ReactiveVar;
chatmessagesCache.set([]);
return chat.find().observeChanges({
added: function(id, doc) {
var tmpArr;
tmpArr = chatmessagesCache.get();
tmpArr.push(doc);
return chatmessagesCache.set(tmpArr);
}
});
});
}
If I leave the route and come back to it, observechanges begins being handled as many times as I've navigated away and returned, for each new record. What's the deal?
If I use subs manager it works as expected, but I don't understand why Meteor.subscribe inside waitOn is so cache/subscription unaware when it ALREADY gets called multiple times per load. Why!? I can't decipher what's causing this behavior at all.
Also, what I'm trying to accomplish is simple. I want to let chat messages that the user's client has received remain on the page even if the chat cursor is no longer publishing them (I'm publishing the last 10 chat messages)
Iron router has reactivity built in, which means when something inside your route function is invalidated, it will repeat the function as well as anything reactive with a Router.current(). These unexpected invalidation runs are a primary reason why folks made the exodus to flow router.
To solve this, you'll want to abstract your code away from the router. You can leave the sub, but I'd suggest you remove the sub's callback from the waitOn and move it into an onRendered callback. If you don't want the history loaded in chunks, you can first do a var collectionCount = chat.find({},{reactive:false}).count() on how many docs are in the collection & then in the added callback you can do something like if (++currentCount === collectionCount) /* add stuff */ to add al the records to the history when it reaches the last record.
On a bigger picture level, consider eliminating the observeChanges & just do an #each over the chat collection in spacebars to show your messages. Fewer cycles, cleaner code.
Iron router just has no management of observations you created yet it manages subscriptions itself, hence the multiple additions.
I figured this out by using a window level variable to check if I'm observing. Even in cases when the subscription is unhooked by iron, if I go back and never re-add the handler, the original observation hook still runs (!). ALSO, if you navigate away and drop the subscription, the handler is no longer called--which is the behavior I want in this scenario (This is all very insane behavior but at least it's now predictable to me )
This is caused by the fact that subscriptions != collections and the API for observations doesn't seem to expose any metadata, unfortunately, so I don't know how the iron router maintainers would account for this. Not to mention you return iron router a subscription, not a collection.
#Matt K if you were correct, this would always be an infinite loop (which admittedly I had a bunch of while trying to solve this) but the posted code is adding too many handlers, not looping indefinitely. Thanks for the post though.
This is what I settled on
Router.route('/gaming',
waitOn: ->
Meteor.subscribe('chat', ->
window.chatmessagesCache = new ReactiveVar(chat.find().fetch().reverse())
if !window.chatListening
window.chatListening = true
after = chat.find().count()
chat.find().observe(
added: _.after(after + 1,(doc) ->
tmpArr = chatmessagesCache.get()
tmpArr.push(doc)
chatmessagesCache.set(tmpArr))
changed : (id, doc) ->
))
I really just wanted to test out a pattern of locally "disconnected" documents. I still may use subs manager because it keeps subscriptions and their handlers alive without rerunning them constantly (which was rerunning the sub handler, which was adding multiple observations)

Meteor wrapAsync works, but restarts server after completion

I'm trying to learn how to use Meteor's wrapAsync helper. I want to use it to call an async function sequentially (not simultaneously). Though my code works, when it completes, the server restarts, which makes me wonder if there is a bug in my code. Unfortunately, there is no message saying why it restarted. Am I missing something?
The code is below and also on my MeteorPad demo.
var doAsyncIO = function (num, callback) {
setTimeout( function () {
// wrapAsync will use the following callback as the basis of returning results synchronously
callback(null, 'This is delayed result #' + num ); // nodeJS form: cb(error,result)
}, 2500); // wait 2.5 seconds before returning result
};
// Now create a synchronous version of doAsyncIO that sleeps, not blocks
// so that the CPU can do other tasks while waiting for the result
var doSyncIO = Meteor.wrapAsync(doAsyncIO);
// Now call doSyncIO twice sequentially (not simultaneously)
console.log('\n*** Starting first call to doSyncIO');
var result1 = doSyncIO(1);
console.log('result1:', result1);
// The following block runs after result1 is set (which is what I want)
console.log('\n*** Starting second call to doSyncIO');
var result2 = doSyncIO(2);
console.log('result2:', result2);
After a code change and after the console logs appear on the terminal, the terminal says the server restarts with no reason provided which makes me wonder if there is a bug in my code!
2015-04-19 Update: the restart message may not actually indicate a problem since it only shows up after a code change. Perhaps it's simply the standard restart message. Nevertheless, it seems like the restart message should really occur before the console logs.
Feel free to comment or fork my MeteorPad demo though to see if it's something else.

How can I run a task inside a meteor method without waiting for it to complete?

I have several function calls in a row that run and wait to return, then the next one runs. After these are run I have one function I want to run, but then I don't want to wait for it to be done before I run my return.
Here is an example of what I mean.
get_card, create_order, create_association and debit_order all need to wait for the previous function to complete before they can run. When I get to Queue.start_account_creation_task I want it to start running, but then let the return on the line below run right away too.
Meteor.methods({
singleDonation: function (data) {
logger.info("Started singleDonation");
//Get the card data from balanced and store it
var card = Utils.get_card(customerData._id, data.paymentInformation.href);
//Create a new order
var orders = Utils.create_order(data._id, customerData.href);
//Associate the card with the balanced customer
var associate = Utils.create_association(customerData._id, card.href, customerData.href);
//Debit the order
var debitOrder = Utils.debit_order(data.paymentInformation.total_amount, data._id, customerData._id, orders.href, card.href);
Queue.start_account_creation_task(customerData._id, data._id, debitOrder._id);
return {c: customerData._id, don: data._id, deb: debitOrder._id};
}
});
Sounds like you need parallel and serial control for tasks. The (as in, 400,000 downloads a day) Node.js module for that is called async, and a Meteor wrapper for it is peerlibrary:async.
Sooner or later you'll need a dedicated background task management package. If async is insufficient, have a look at my evaluation of packages to control background tasks in Meteor.
The thing that seemed to work the best for what I was trying to do was to just use a Meteor.setTimeout({}). It might seem like an odd choice, but it does everything I needed, including setting the Meteor Environment so that I didn't have to do any BindEnrironment call. It also breaks out of the current thread of calls, which means it then returns the result to the client and a second later finishes the rest of the calls (which are to external APIs that I didn't need my users sitting there waiting for).

How to debug slow meteor methods?

A number of my meteor methods have mysteriously slowed down recently. Whereas they used to be quite snappy, many are taking 10 or so seconds.
Things not causing the slowdown:
Additional functionality, the slowed sections of the codebase haven't been changed significantly
Machine load (cpu load hovering around 30%)
Additional DB load (no new queries added)
transfer time of the return data (returns undefined)
blocking method (I've tried with this.unblock() within the method)
I did debugging by using console.time() / console.timeEnd() on both the server and client side. The server side code takes about .3 seconds to run, but the client doesnt get the callback until about 11 seconds after the meteor.call() ...
This is the server method:
function cancelSomething(somethingId, reason) {
console.time('cancelSomething method');
check(somethingId, String);
check(reason, String);
if (!AuthChecks()))
throw new Meteor.Error(401, 'Not Authorized');
var something = MySomethings.findOne({'_id': somethingId});
if (!something)
throw new Meteor.Error(404, 'Something not found');
var returnVal = SomethingService.cancel(something, reason);
console.timeEnd('cancelSomething method'); // <--- prints "cancelSomething 350ms" or there abouts
return returnVal;
}
clientSide:
console.time('meteorCall');
Meteor.call('cancelSomething', this._id, reason, function(err) {
if (err) {
console.log('an error occurred', err);
}
console.timeEnd('meteorCall'); // <--- prints "meteorCall 11500" or so
});
EDIT:
I have noticed there is some correlation with the quantity of docs within the "somethings" in the db. w/ 500 documents it takes about 1 second to receive the return on the client, with 5000 it takes about 8.5 seconds ...
Interesting. I think this one is hard to answer without knowing more about your app, but I have some suggestions that could help steer you in the right direction.
blocking
If we can assume that the timers are working properly, what could be happening is that the server is unable to begin execution of the method because another method call by the same client is already in progress. Have a look at unblock in the docs. The answer may be as simple as putting a this.unblock at the top of one of your methods.
syncing
If SomethingService.cancel does something which results in a lot of DDP traffic, that could tie up the client for a while and make it unable to execute your callback. For example if it:
modified or created a lot of documents which then had to be synced to the client
indirectly caused an expensive subscription to be rerun (my money is on this one)
Updated Answer
It seems the problem had to to with a call to observe, which makes a lot of sense given your high CPU load. Frankly, it's a little silly that I didn't suggest this because I have already answered a similar question here. If you want to try to keep the observe, here are some additional suggestions:
Use oplog tailing.
Try to narrow the scope of the observe as much as possible using selectors which are currently supported by the oplog observe driver. The supported selectors should improve at or before meteor 1.0.
Limit the fields to only those you need.
Check that oplog tailing is working by adding the facts package.

Resources