I have a routine to update a value in the DB and then look for it on a one second timer. Here is a simplistic setup...
function checkStatusAndDoWork(){
userMongooseModel.find({'someCondition': { $gte:(new Date()) }}, function(err, userModel){
if (userModel.length > 0) { //there is only one document in the return.
doSomeWorkThatTakes20seconds();
// Update the Mongo document with a new next time
userMongooseModel.update( {_id:userModel[0]._id}, {'someCondition': new Date() + 10000}, function(err, numAffected){
console.log('Checkpoint 1');
setTimeout(checkStatusAndDoWork, 1000); //repeat the loop after 1 second.
})
} else {
console.log('Checkpoint 2');
setTimeout(checkStatusAndDoWork, 1000); // otherwise repeat the loop after 1 second anyways.
}
}
}
The situation -
Normally, everything works OK. I see the following:
Checkpoint 1
Checkpoint 2
Checkpoint 2
...
Checkpoint 2
Checkpoint 1
Checkpoint 2
Checkpoint 2
...
But if I open MongoExplorer and start reviewing the document, then I see the following if I happen to time it just right...
Checkpoint 1
Checkpoint 2
Checkpoint 2
...
Checkpoint 2
Checkpoint 1
Checkpoint 1
Checkpoint 1
Checkpoint 1
Checkpoint 1
Checkpoint 2
Checkpoint 2
...
It appears that the update goes into a Mongo queue and so the document is not updated immediately. This causes the find() to return true and go to 'Checkpoint 1' repeatedly until the db write is complete.
How can I avoid this race condition?
Note: I rewrote this How do I use setTimeout with double callbacks in javascript question to simplify.