ioSocket не излучает браузер на сервере с большой нагрузкой

Некоторые запросы, которые могут быть отправлены на мой сервер nodejs, требуют интенсивной обработки (например, 5000 файлов). Поскольку обработка запроса займет некоторое время, я хочу отображать прогресс в браузере. Для этого я использую io-сокет. Регулярно сервер отправляет клиенту прогресс, например, ioSocket.emit("log", "progress 24%),
Однако, если отправка прогресса клиенту обычно работает, когда имеется большое количество файлов, это не так. Ничего не отправлено в браузер.
Я уверен, что процесс идет хорошо, так как я регистрирую прогресс на терминале узла, и там он выглядит как ожидалось.

Мне интересно, что я могу сделать, чтобы событие ioSocket.emit работало в случае большой нагрузки, потому что именно там наиболее полезно видеть прогресс.

Функция обработки файлов выглядит следующим образом:

var child_process = require("child_process");

function (ioSocket) {

  ioSocket.emit("log", "start")

  var ratingCounts = 0;
  var listOfFilesRatings = []

  _.each(listOfFilesPaths, function(path, i){

    child_process.exec("exiftool -b -Rating "+ path, function(err, stdout){

      if (err) console.log(err)
      else {

        listOfFilesRatings.push(stdout);
        ratingCounts++;

        ioSocket.emit("log", "rating test progress "+ ratingCounts)

      };

    });

    ioSocket.emit("log", "each progress "+ i)

  });


}

В этом примере только первый "стартовый" emit будет запущен в браузере.

Однако, если я сделаю следующее:

function (ioSocket) {

  ioSocket.emit("log", "start")

  for (i=0; i<1000; i++) {

    ioSocket.emit("log", "each progress "+ i)

  };

}

все работает отлично, и я получаю "начало" и все "каждый прогресс" отправляется в браузер.

1 ответ

Решение

Если вы обрабатываете 5000 файлов, ваша схема с _.each() а также child_process.exec() запустит 5000 процессов exiftool одновременно. Это, скорее всего, поставит любой компьютер, за исключением, возможно, большого железа на колени. Вероятно, вам следует запускать не более N из них в то время, когда вы запускаете некоторые тесты производительности на вашем конкретном оборудовании, чтобы определить, каким должно быть N (вероятно, меньше 10).

Вот один из способов сделать это:

var child_process = require("child_process");

function processFiles(ioSocket) {

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

        ioSocket.emit("log", "start")

        let ratingCounts = 0;
        let listOfFilesRatings = [];
        const maxInFlight = 10;
        let inFlightCntr = 0;
        let fileIndex = 0;

        function run() {
            // while room to run more, run them
            while (inFlightCntr < maxInFlight && fileIndex < listOfFilesPaths.length) {
                let index = fileIndex++;
                ++inFlightCntr;
                ioSocket.emit("log", "each progress " + index)
                child_process.exec("exiftool -b -Rating " + path, function(err, stdout) {
                    ++ratingCounts;
                    --inFlightCntr;
                    if (err) {
                        console.log(err);
                        listOfFilesRatings[index] = 0;
                    } else {
                        listOfFilesRatings[index] = stdout;
                        ioSocket.emit("log", "rating test progress " + ratingCounts)
                    }
                    run();
                });
            }
            if (inFlightCntr === 0 && fileIndex >= listOfFilesPaths.length) {
                // all done here
                console.log(listOfFilesRatings);
                resolve(listOfFilesRatings);
            }
        }
        run();
    });
}


processFiles().then(results => {
    console.log(results);
});
Другие вопросы по тегам