Meteor observe running forever - meteor

According to observe docs, I must define and call a stop function, or my observer will run forever. The point, is how to call stop if the user decided to close his browser before the expected time, for example? How can I call stop if a conection is dead?

You don't actually need to worry about disconnects. Any time the subscription stops (whether the client disconnects, or calls unsub, or you call this.stop), the server will run all the registered onStop handlers before tearing down the active subscription. (Teardown doesn't happen immediately on disconnect, by the way, but it will eventually. The idea is to wait a bit, in case the client tries to reconnect and resume its session.)
What you do need to do is make sure to register an onStop handler that cleans up any resources your code used. Again, that needs to happen anytime the subscription is stopped. onStop is the right hook. It's critically important to call stop on an active observe, for example, just like in the first code stanza in the example.

To do this, you can call it inside your publish:
this.session.socket.on("close", function() { /*do your thing*/});
So, if you wanna stop an observer...
Meteor.publish("something", function () {
// ...
// your observers code here
// ...
self.onStop(function () {
handle.stop();
});
this.session.socket.on("close", function() {
handle.stop();
});
});
Answer found here. Thanks goes to Zhou Huabing.

Related

Meteor.call is very slow when responding back

I am facing performance problem with Meteor.call(). I have a method on server side which gets execute within a millisecond but when I seek a response in the client side, it is taking long to get the response data inside the callback function. Is anyone experience the problem before?
I was using Meteor 1.12.1 and updated to Meteor 2.1.1 hoping to solve the problem by updating but I didn't find any difference.
Update: I am facing issue on all environment (osx, linux, windows).
For eg: This is my server code
Meteor.methods({
newEntry() {
//This method is executed within millisecond
}
})
This is my client code
function submitEntry(data) {
Meteor.call(
'newEntry',
data,
(error, res) => {
//Here I am getting the response after long wait.
},
);
}
Can somebody help me on this?
I found the solution. As per the Meteor docs.
Once the Method has finished running on the server, it sends a result message to the client with the Method ID generated in step 2, and the return value itself. The client stores this for later use, but doesn’t call the Method callback yet. If you pass the onResultReceived option to Meteor.apply, that callback is fired.
Ref: https://guide.meteor.com/methods.html#advanced-boilerplate
So if you want your call back to be triggered once the server method return the value then you can use Metor.apply method with the option onResultReceived.
Meteor.apply(
"methodName",
[...params],
{
onResultReceived: function() {
// Whatever you want to do after callback.
}
}

meteor: how to stop asynchronous call?

Is it possible to stop (kill) asynchronous Call?
In my app I have at client side sth like:
Meteor.call('doCalculation', function(err, result) {
//do sth with result
});
'doCalculation' may take long time (this is ok) I dont want user to start new call when he/she has already one running call, I want to allow user to stop current call and submit new one. How correctly do this?
The only idea I have is to communicate between client and server using mongo. In some place in 'doCalculation' function I can observe some mongo document/collection and based on this do sth in the function (e.g. call exception). Do you have any better ideas?
You can use a semaphore for this purpose. When the semaphore is 1, requests are allowed to be sent. When the semaphore is 0, requests are not allowed to be sent. The semaphore should be 1 by default and just before you send the request, you need to set it to 0. When a response is successful, you set the semaphore back to 1.
As about the timeout: You could use a time out using setTimeout after sending the request, like this:
if (semaphore) {
var isTimedOut = false;
var isSuccess = false;
semaphore = 0; //No need to use var keyword, as this should be declared outside of this scope
Meteor.call('doCalculation', function(err, result) {
isSuccess = true;
//do sth with result
});
setTimeout(function() {
if (!isSuccess) {
isTimeout = true;
//do something else, to handle the time out state
}
}, 10000);
}
This is tricky, because you cannot generally set timeouts from the client's point of view. You don't need to, for a bunch of architectural reasons. The most important thing is that if you lose network connectivity or the server crashes (two cases timeouts are designed to manage), the client is aware immediately because it is disconnected. You can use Meteor.status().connected if this happens often.
It sounds like you're running a long calculation on the server. My suggestion is to return a calculationId immediately, and then update a collection with progress, e.g., CalculationProgresses.update(calculationId, {$set: {progress: currentProgress}}) as you calculate. Your UI can then update the progress reactively, in the most convenient way possible.
Note, that when you do run long calculations on the server, you need to occasionally "yield," giving the chance for other work to happen. Node, on which Meteor is based, is tricky for long calculations if you don't master this notion of yielding. In Meteor, you can yield easily by updating a collection (e.g., your progress collection). This will solve lots of problems you're probably experiencing as you write your application.
i think you need a server-side solution for this. if you go with a client-side solution, you don't handle 2 cases:
the user reloads their browser
the user uses 2 browsers
i would create these methods:
isCalculationActive() -- this checks if the user already has a calculation active. on the server, you can either keep that fact in memory or write it to the db. on the client, if this returns false, then you can proceed to call doCalculation(). if true, you can give the user a popup or alert or something to ask if they want to cancel and proceed.
doCalculation() -- this cancels any outstanding calculation by that user and starts a new one.
with these implemented, the user can reload their browser w/o affecting either the running calculation or correct behavior. and if they try a 2nd browser, everything should still work as expected.
if you want to give the user the option to simply stop the job and not start a new one, then you can simply create:
cancelCalculation() -- this cancels any outstanding calculation by that user.

Can someone explain how Meteor.defer() works?

So... Meteor.defer(function(){ // stuff }) isn't in the docs:
https://github.com/meteor/meteor/issues/2176
But this links seems to say that it's simply equivalent to
Meteor.setTimeout(function(){ // stuff }, 0);
If that's the case, how does this do, um, anything? It's basically saying "wait for 0 ms and then run the function".
So... it runs the function instantly.
What am I missing here? Is this kind of like Tracker.afterFlush or something? Does it somehow wait for "things" (what kind of things?) to finish before running?
I see Meteor.defer() a lot on SO being used as a bit of a hack on added helper methods to run after the dom is (somewhat) loaded - basically to get the same effect as running code inside of a Template.foo.rendered method.
However, the main (and best) use of Meteor.defer is to run a task asynchronously.
Let's say we have an app where we are sending an email. On the server, it may take several seconds for that to process inside of a meteor method, slowing down your application drastically. However, if you wrap that process in a Meteor.defer the email processing won't block execution, the email still sends (when it gets a chance, not instantly), but everything runs much faster, since the code that follows isn't waiting. There is a great example lesson about deferring execution at Bulletproof Meteor.
You can actually get the same effect with a setTimeout(f,0) - if you have a slow function, you could wrap it in the setTimeout and the rest of the code will complete, and 'defer' the slow process in the timeout, so although it doesn't seem like it, setTimeout(f,0) does actually have a pretty useful purpose!
To see an example of this in action, here's a fiddle, open the console and watch where 'foo' logs.
I faced some issue in my project because of asynchronous callback. Inside onCreated i was making a server Meteor.call and set the response inside reactiveVar. And i was doing something inside onRendered with that reactiveVar. Every time reactiveVar was showing undefined.
So i used Meteor.defer(function(){...}) inside onRendered and it sloved my issue.
Here is some demo with and without using Meteor.defer()
Template.myTemplate.onCreated(function () {
var instance = this;
instance.myTemplateModel = new ReactiveDict();
Meteor.call('all-user', function(err, res){
if(res){
console.log('inside callback');
instance.myTemplateModel.set('users', res);
}
});
});
Template.myTemplate.onRendered(function () {
var instance = this
console.log('rendered start');
Meteor.defer(function(){
console.log(instance.myTemplateModel.get('users'));
});
console.log('render end');
});
Console:
/*Without Meteor.defer()*/ | /*With Meteor.defer()*/
render start | inside callback
undefined | render start
render end | render end
inside callback | [Object, Object, Object]

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.

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

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!

Resources