ilikeopensource
ilikeopensource

Reputation: 375

Meteor method got triggered multiple times

I have a fairly simple Meteor application.

I tried to send newsletter to about 3000 users in my list and things went wrong. A random set of users got multiple emails (between 41 to 1).

I shut the server down as soon I noticed this behavior. around 1300 emails were sent to 210 users. I am trying to figure out what happened and why.

Here is the code flow:

SendNow (client clode) --> SendNow (server method) --> populateQue (server function) --> processQue(server function) --> sendEmails (server method)

Client side code :

'click .sendNow': function(){
   /* code that forms data object */
   Meteor.call('sendNow',data);
}

Server code : server/method.js

Meteor.methods({
 'sendNow' : function(data){
  if(userWithPermission()){     
    var done = populateQue(data);
    if(done)
      processQue();
    return {'method':'sendNow','status':'ok'}
 },
 'sendEmails': function(data){
   this.unblock();
   var result = Mandrill.messages('send', data);// using external library
   SentEmails.insert(data);//Save sent emails in a collection
 }
});

Function on server : server/utils.js

populateQue = function(data) {
  /* code to get all users in to array */
  MessageQue.remove();//Remove all documents from the Que
  for (var i=0; i<users.length; i++) {
    MessageQue.insert({userId: users[i]._id});
  }
  return true;
}

processQue = function(){
  var messageQue = MessageQue.find({}).fetch();
  for(i=0; i < messageQue.length; i++){
    Meteor.call('sendEmails', data);
    MessageQue.remove({_id: messageQue[i]._id});//Remove sent emails from the Que
  }
}

My first hunch was MessageQue got messed up as I am removing items while processQue is using it but i was wrong. I am unable to simulate this behavior again after few tests

  1. Test 1 : replaced Mandrill.message('send',data) with Meteor._sleepForMs(1000); - Only one email/person was seen in SentEmails collection.

  2. Test 2 : Put Mandrill in Test mode (had to use different API key) and re ran the code with couple of log statements. - Only one email/person was seen in SentEMails and also in Mandrill's interface.

It's definitely not external library. its somewhere in my code or in the way I understood meteor to work.

Only one thing I noticed is an error occurred while accessing SentEmails collection through another view code. I have a view that displays SentEmails on the client with date as filter.

Here is the error :

Exception from sub sentEmailDocs id 9LTq6mMD4xNcre4YX Error: 
  Exception while polling query 
    {
      "collectionName":"sent_emails",
      "selector":{"date":{"$gt":"2015-07-09T05:00:00.000Z","$lt":"2015-07-11T05:00:00.000Z"}},
      "options":{"transform":null,"sort":{"date":-1}}
    }: 
  Runner error: Overflow sort stage buffered data usage of 33565660 bytes exceeds internal limit of 33554432 bytes

Is this the smoking gun? Would this have caused the random behavior?

I have put couple checks to prevent this from happening but I am puzzled on what might have caused and why? I will be happy to provide more information. Thanks in advance to who ever is willing to spend few mins on this.

Upvotes: 0

Views: 227

Answers (1)

Matt K
Matt K

Reputation: 4948

Shot in the dark here, but the remove method takes an object, otherwise it doesn't do anything. MessageQue.remove() probably didn't clear the queue. You need MessageQue.remove({}). Test the theory by doing an if (MessageQue.find().count() > 0)... after the remove.

If you're set on having a separate collection for the queue, and I'm not saying that's a bad thing, I'd set the _id to be the userId. That way you can't possibly send someone the same message twice.

Upvotes: 0

Related Questions