1

编辑:我在如何避免 Nodejs 和 Mongoose 应用程序中的竞争条件中使用更简单的代码和更多信息重写了这个问题?. 我将其保留原样,以便人们可以根据需要参考详细的代码。

我有一个带有子文档的 Mongoose 节点设置。我需要调用一个函数来使用 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?

4

1 回答 1

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);
      })
    })
}
于 2013-12-12T20:56:47.093 回答