编辑:我在How to avoid a race condition in Nodejs and Mongoose app?中用更简单的代码和更多信息重写了这个问题。我保留原样,以便人们可以根据需要参考详细的代码。
我有一个包含子文档的Mongoose,Node设置。我需要使用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?
答案 0 :(得分:0)
未经测试但你可以试试这个:
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);
})
})
}