2017-09-15 1 views
0

자바 스크립트를 사용하여 이전 루비 스크립트를 포팅하여 cron 인스턴스로 설정하여 일정대로 실행합니다. 이 함수는 우리의 mysql 데이터베이스를 쿼리하고 우리 제품에 대한 인벤토리 정보를 검색 한 다음 거래 파트너 api에 요청을 보내 사이트의 인벤토리를 업데이트합니다.비동기/동시성 문제로 인한 NodeJS 루프 문제

노드로 인해 동시성 문제가 있습니다. 요청 당 1000 개의 항목으로 요청을 청크에 넣고 10K 개의 제품을 보내고 있습니다. 문제는 각 요청이 매번 마지막 1000 개 항목을 보내는 것입니다. while 루프 내부의 for 루프는 json 요청 본문 작성을 완료하기 전에 앞으로 이동합니다. while 루프에서 anon setTimeout 함수를 작성하여 처리하고, 요청 함수와 변수를 전달하는 객체를 작성하고 while 루프가 완료되면이를 반복하도록 배열에 채우는 방법을 시도했지만 시도 중입니다. 같은 결과. 각 요청이 올바른 항목 배치를 얻을 수 있도록 처리하는 가장 좋은 방법이 무엇인지 확실하지 않습니다. 요청 뚜껑에 부딪치지 않기 위해 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

이것은 폐쇄 또는 비동기 문제가 아닙니다. 내가 작성한 요청 개체는 얕은 복사본 대신 개체에 대한 참조를 사용하여 데이터가 모두 끝 배열의 동일한 개체 참조에 연결되도록하는 것이 었습니다.

관련 문제