Reputation: 375
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
Test 1 : replaced Mandrill.message('send',data)
with Meteor._sleepForMs(1000);
- Only one email/person was seen in SentEmails
collection.
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
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