编辑:我用更简单的代码和How to avoid a race condition in Nodejs and Mongoose app?中的更多信息重写了这个问题。我将其保留为原样,以便人们可以根据需要参考详细的代码。
我有一个带有子文档的猫鼬节点设置。我需要调用函数以使用setTimeout根据某些条件更新数字。但是,有时由于回调未快速返回而进入竞争状态。这是一个示例方法。
function myProcessPump(){
//Get top level documents based on some condition
UserInfo
.where('some_condition').lte(new Date())
.exec(function(err, UserInfoRetArray){
if (!err) {
if (UserInfoRetArray.length > 0){
//Iterate thru the top level documents
for (var i = 0; i < UserInfoRetArray.length; i++){
//Iterate thru sub-documents
for (var j = 0; j < UserInfoRetArray[i].someItems.length; j++){
// do some work...
do_work(UserInfoRetArray[i].someItems[j]);
//update status in db
set['someItems.$.some_condition'] = new Date((new Date()).getTime() + 10000) ;
UserInfo.update({_id: UserInfoRetArray[i]._id, "someItems._id":UserInfoRetArray[i].someItems[j]._id},
{$set: set}, function(err, numAffected) {
//set timeout so myProcessPump is called again.
setTimeout(myProcessPump, 1000);
});
}
}
} else {
//set timeout so myProcessPump is called again.
setTimeout(myProcessPump, 1000);
// I suspect this gets called when the previous call back does not
// complete in time causing the mulitple timers running in parallel.
}
} else {
//set timeout so myProcessPump is called again.
setTimeout(myProcessPump, 1000);
}
})
}
我简化了代码以解释我想要的。如何在不发生争用条件的情况下成功调用setTimeout?
最佳答案
未经测试,但您可以尝试以下方法:
function myProcessPump() {
//Get top level documents based on some condition
UserInfo
.where('some_condition').lte(new Date())
.exec(function(err, UserInfoRetArray) {
//Wrap everything in an async function with a callback
var processUser = function(done) {
if (!err) {
if (UserInfoRetArray.length > 0) {
//Iterate thru the top level documents
for (var i = 0; i < UserInfoRetArray.length; i++) {
//Iterate thru sub-documents
for (var j = 0; j < UserInfoRetArray[i].someItems.length; j++) {
// do some work...
do_work(UserInfoRetArray[i].someItems[j]);
//update status in db
set['someItems.$.some_condition'] = new Date((new Date()).getTime() + 10000);
UserInfo.update({
_id: UserInfoRetArray[i]._id,
"someItems._id": UserInfoRetArray[i].someItems[j]._id
}, {
$set: set
}, function(err, numAffected) {
done();
});
}
}
} else {
done();
}
} else {
done();
}
}
//Call async function and when done redo the whole thing
processUser(function() {
//probably done need the timeout and can just call myProcessPump unless you really need a delay
myProcessPump();
//setTimeout(myProcessPump, 1000);
})
})
}