NodeJS, как заставить асинхронный цикл для ожидания разрешения HTTP-запроса, прежде чем перейти к следующей итерации, чтобы мы не получили ошибку EMFILE? - PullRequest
0 голосов
/ 01 июля 2018

Я пытаюсь интегрировать в пользовательский API, я получаю несколько строк из базы данных, а затем для каждой строки, которую я подключаю к API. Дело в том, что когда база данных возвращает 3000 строк или меньше, API возвращает правильные ответы, когда я получаю POST более 3000, я получаю следующее:

EMFILE ERROR -> ОС не позволяет открывать больше сокетов

Я полагаю, что API не разрешит более 3000 HTTP-запросов. Я попробовал подход обещания / асинхронного ожидания, чтобы дождаться окончания HTTP-запроса, но безуспешно, только когда он работал, когда я добавил функцию ожидания для ожидания 200 мс или более

Вот моя оригинальная функция:

    async function send_data(rows){
    let a=0;    
    log.info("Emails to integrate: "+rows.length);
    if(rows.length){
      for(const row of rows){
        log.info(row.email+" --- "+row.name+" --- "+row.id);
        await integrate_data(row,a);
        //await sleep(50);
        a++;
      }
      log.info("Finished integration, setting last ID");
    } else {
      log.info("No data to integrate");
    }
}

function integrate_data(row,counter){
        var options = {
          "method": "POST",
          "hostname": "API-URL",
          "path":"PATH/EMAIL/"+row.email,
          "headers": {
            "Content-Type": "application/json"
          }
        };
        var req = http.request(options, function (res) {
          var chunks = [];

          res.on("data", function (chunk) {
            chunks.push(chunk);
          });

          res.on("end", function () {
            var body = Buffer.concat(chunks);
            log.info(body.toString());
          });
        });

        let obj;
          obj = { 
            key1: row.name,
            key2: row.id, 
            key3: row.iterationNumber
         }

        req.write(JSON.stringify(obj));
        req.end();
}

function sleep(ms) {
  return new Promise(resolve => setTimeout(resolve, ms));
}

есть ли в любом случае ждать завершения транзакции HTTP и затем перейти к следующей итерации, чтобы функция могла открыть соединение, отправить данные, закрыть соединение и затем дать сигнал для перехода к следующей итерации?

Заранее спасибо

1 Ответ

0 голосов
/ 01 июля 2018

await integrate_data(...) не делает то, что вы думаете. Вы не ждете, пока запрос будет выполнен, ваш код будет выполняться

req.write(JSON.stringify(obj)); 
req.end();

и переходите к следующей итерации.

Чтобы await работал должным образом, integrate_data должен возвращать Promise и должен разрешаться после завершения запроса.

function integrate_data(row, counter) {
    var options = {
        "method": "POST",
        "hostname": "API-URL",
        "path": "PATH/EMAIL/" + row.email,
        "headers": {
            "Content-Type": "application/json"
        }
    };

    return new Promise((resolve, reject) => {

      var req = http.request(options, function(res) {
          var chunks = [];

          res.on('error', reject);

          res.on("data", function(chunk) {
              chunks.push(chunk);
          });

          res.on("end", function() {
              var body = Buffer.concat(chunks);
              log.info(body.toString());
              resolve(body.toString()); // resolve promise
          });
      });

      let obj;
      obj = {
          key1: row.name,
          key2: row.id,
          key3: row.iterationNumber
      }

      req.write(JSON.stringify(obj));
      req.end();
    });
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...