Meteor_double_event_call
Recently, when working with Meteor methods, I've stumbled upon an odd problem.
While going into debug mode:

1
meteor debug

I've suddenly noticed some methods are being called twice. I wasn't sure when exactly it happens but I've noticed it happens more often when the method has a bunch of async calls.

I started Googling to see if this is a known bug, and found this: Method called once but executed twice.

This answer in particular is what I found interesting:

...During the yield, the background observe thread notices that the user object is gone and disconnects the connection. The client sees this and reconnects; because the removeUser method was in flight and never got a response, it runs it again.

So while the reason for disconnecting was different on my end (I wasn't deleting the user in my methods, but I was manipulating user data), I started to think that it's related to the client call.

Another evidence for this was the dead end I reached when examining the call stack. Once compared, I realized the call stacks are identical, which probably points back to the client calling the function again.

How did I fix this?
The workaround may sound silly, but because the method was a multi-stages kind of thing, I decided to have a status, so we know "where we are" in the process.
The status should be written right before calling the method, and be overwritten as soon as the method starts.
Because Session is not available on server side, I used the database to store the status.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
/* wherever you call your methods, e.g. where the template events are */
Meteor.call( 'setUserStatus', 'method1', 'execute' );
Meteor.call( 'method1' );
/* methods.js */
Meteor.methods({
  setUserStatus: function( method, status ) {
    Meteor.users.update(
{ _id: this.userId },
{ $set: { method + '_status':  status } }
);
  },
method1: function() {
   var user = Meteor.user();
   if ( user.method1_status === 'execute' )
     Meteor.call( 'setUserStatus', 'method 1', 'running' )
   else
     return false; //second call
   //...Functions content...
})

Don't forget to expose the fields on publications.js (or wherever your publications are), otherwise the user object won't have them as attributes.

Bonus: Push to a sub-attribute in MongoDB

If you're going with a single attribute (e.g. 'status') that will hold sub-arrays of the different statuses, pushing to those arrays will only work when using $push.
In this example, we have an array within status that's called 'method1', and we're pushing the status 'running' to it:

1
2
3
4
Meteor.users.update(
	{_id: this.userId},
	{$push: { 'status.method1': 'running' }}
);