1

編集: Nodejs と Mongoose アプリで競合状態を回避する方法で、より単純なコードと詳細情報を使用してこの質問を書き直しました。. 必要に応じて詳細なコードを参照できるように、これをそのまま残しました。

サブドキュメントを使用して、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 を正常に呼び出すにはどうすればよいですか?

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 に答える