Musical Shore Musical Shore - 5 months ago 13
Node.js Question

"Race like" condition with Mongoose

I have a process that triggers a number of requests that in turn trigger off a number of webhooks. I know the process is complete when I've received all of my webhooks. My model looks something like this.

{
name: 'name',
status: 'PENDING',
children: [{
name: 'child1',
status: 'PENDING'
}, {
name: 'child2',
status: 'PENDING'
}]

}


The idea is as the webhooks come in, I update the subdoc to
COMPLETE
. At the end of each update I check if the others are complete and if they are, I set
status='COMPLETE'
on the parent. It looks like one invocation of the service is marking it as
COMPLETE
after another invocation has determined it was still
PENDING
but before that second invocation has saved. When the second one saves, it overwrites
COMPLETE
with
PENDING
on the parent.

Here is the code from my schema:

methods: {
doUpdate: function(data) {
var child = this.children.id(data.childId);
child.status = 'COMPLETE';
if (_.every(this.children.status, 'COMPLETE'))
this.status = 'COMPLETE';
return this.save();
}
}

Answer

The solution is to first find and update the status in one operation, using a variant of mongo's findAndModify method, and then check if the other children have completed. I was trying to do two updates in one operation. By breaking it up into two steps, I know that when I check the statuses of the other children, all other invocations will have the most recent state of the document and not get a false reading while another invocation is waiting for save() to complete.