2017-09-15 16 views
0

私は、古いRubyスクリプトをjavascriptを使用して移植しています。この関数をcronインスタンスとして設定すると、スケジュールどおりに実行されます。この関数はmysqlデータベースに問い合わせて、商品の在庫情報を取得し、取引パートナーのAPIにリクエストを送信して、自分のサイトの在庫を更新します。非同期/同期性の問題によるNodeJSループの問題

ノードa-synchronicityのため、私は問題にぶつかっています。リクエストごとに1000件のリクエストをチャンクする必要があり、10k個の製品を送信しています。問題は、毎回最後の1000個のアイテムを送信するだけです。 whileループ内にあるforループは、json要求ボディの作成が完了する前に前進しています。私はwhileループの中でsetTimeout関数を作成しようとしましたが、要求関数と変数を渡してオブジェクトを作成してオブジェクトを作成し、それを配列に入れてループを完了させましたが、同じ結果。各リクエストが正しいバッチのアイテムを取得できるように、それを処理する最良の方法は何か分かりません。また、リクエストの上限に達しないように1000アイテムの各リクエストの間に3分待つ必要があります。

query.on('end',()=>{ 
        connection.release(); 
        writeArray = itemArray.slice(0), 
        alteredArray = []; 
        var csv = json2csv({data: writeArray,fields:fields}), 
        timestamp = new Date(Date.now()); 
        timestamp = timestamp.getFullYear() + '-' +(timestamp.getMonth() + 1) + '-' + timestamp.getDate()+ ' '+timestamp.getHours() +':'+timestamp.getMinutes()+':'+timestamp.getSeconds(); 
        let fpath = './public/assets/archives/opalEdiInventory-'+timestamp+'.csv'; 

        while(itemArray.length > 0){ 
         alteredArray = itemArray.splice(0,999); 
         for(let i = 0; i < alteredArray.length; i++){ 
          jsonObjectArray.push({ 
           sku: alteredArray[i]['sku'], 
           quantity: alteredArray[i]["quantity"], 
           overstockquantity: alteredArray[i]["osInv"], 
           warehouse: warehouse, 
           isdiscontinued: alteredArray[i]["disc"], 
           backorderdate: alteredArray[i]["etd"], 
           backorderavailability: alteredArray[i]["boq"] 
          }); 
         } 

         var jsonObject = { 
          login: user, 
          password: password, 
          items: jsonObjectArray 
         }; 

         postOptions.url = endpoint; 
         postOptions.body = JSON.stringify(jsonObject); 
         funcArray.push({func:function(postOptions){request(postOptions,(err,res,body)=>{if(err){console.error(err);throw err;}console.log(body);})},vars:postOptions}); 
         jsonObjectArray.length = 0; 
        } 
        var mili = 180000; 
        for(let i = 0;i < funcArray.length; i++){ 
         setTimeout(()=>{ 
          var d = JSON.parse(funcArray[i]['vars'].body); 
          console.log(d); 
          console.log('request '+ i); 
          //funcArray[i]['func'](funcArray[i]['vars']); 
         }, mili * i); 
        } 
       }); 
      }); 
+0

[mcve]に減らすことはできますか? (あなたは途中で問題を見つけるかもしれません。) –

+0

私はコード例を更新しました。 –

答えて

0

あなたはasync/awaitまたはPromiseがノードJSで非同期アクションを処理する必要があります。 Async/awaitをサポートするノードのバージョンがあるかどうか分からないので、私は約束ベースのソリューションを試しました。

query.on('end',() => { 
 
    connection.release(); 
 
    writeArray = itemArray.slice(0), 
 
     alteredArray = []; 
 
    var csv = json2csv({ data: writeArray, fields: fields }), 
 
     timestamp = new Date(Date.now()); 
 
    timestamp = timestamp.getFullYear() + '-' + (timestamp.getMonth() + 1) + '-' + timestamp.getDate() + ' ' + timestamp.getHours() + ':' + timestamp.getMinutes() + ':' + timestamp.getSeconds(); 
 
    let fpath = './public/assets/archives/opalEdiInventory-' + timestamp + '.csv'; 
 

 
    var calls = chunk(itemArray, 1000) 
 
         .map(function(chunk) { 
 
          var renameditemsArray = chunk.map((item) => new renamedItem(item, warehouse)); 
 
          var postOptions = {}; 
 
          postOptions.url = endpoint; 
 
          postOptions.body = JSON.stringify({ 
 
           login: user, 
 
           password: password, 
 
           items: renameditemsArray 
 
          }); 
 
          return postOptions; 
 
         }); 
 
    sequenceBatch(calls, makeRequest) 
 
     .then(function() { 
 
      console.log('done'); 
 
     }) 
 
     .catch(function(err) { 
 
      console.log('failed', err) 
 
     }); 
 

 
    function sequenceBatch (calls, cb) { 
 
     var sequence = Promise.resolve(); 
 
     var count = 1; 
 
     calls.forEach(function (callOptions) { 
 
      count++; 
 
      sequence = sequence.then(()=> { 
 
       return new Promise(function (resolve, reject){ 
 
        setTimeout(function() { 
 
         try { 
 
          cb(callOptions); 
 
          resolve(`callsequence${count} done`); 
 
         } 
 
         catch(err) { 
 
          reject(`callsequence ${count} failed`); 
 
         } 
 
        }, 180000); 
 
       }); 
 
      }) 
 
     }); 
 
     return sequence; 
 
    } 
 
    function makeRequest(postOptions) { 
 
     request(postOptions, (err, res, body) => { 
 
      if (err) { 
 
       console.error(err); 
 
       throw err; 
 
      } 
 
      console.log(body) 
 
     }); 
 
    } 
 

 
    function chunk(arr, len) { 
 
     var chunks = [], 
 
      i = 0, 
 
      n = arr.length; 
 
     while (i < n) { 
 
      chunks.push(arr.slice(i, i += len)); 
 
     } 
 
     return chunks; 
 
    } 
 

 
    function renamedItem(item, warehouse) { 
 
     this.sku = item['sku'] 
 
     this.quantity = item["quantity"] 
 
     this.overstockquantity = item["osInv"] 
 
     this.warehouse = warehouse 
 
     this.isdiscontinued = item["disc"] 
 
     this.backorderdate = item["etd"] 
 
     this.backorderavailability= item["boq"] 
 
    } 
 
});

あなたはこのスニペットを試してみてくださいし、その場でそれを作ったので、私はそれをテストすることができませんでした?それが動作するかどうか私に教えてもらえ。コアロジックはsequenceBatch関数内にあります。その答えは、別のquestionに基づいており、タイムアウトと約束がどのように連動するかを説明しています。

0

これは閉鎖または非同期の問題ではないことがわかりました。私が構築していた要求オブジェクトは、浅いコピーではなくオブジェクトへの参照を使用しているため、データはすべてエンディング配列の同じオブジェクトrefにリンクされていました。