Stdout из Node.js child_process exec прерван

В Node.js Я использую команду exec модуля child_process для вызова алгоритма в Java, который возвращает большое количество текста в стандартную версию, из которой я тогда разбираюсь и использую. Я могу захватить его в основном, но когда он превышает определенное количество строк, содержимое отключается.

exec("sh target/bin/solver "+fields.dimx+" "+fields.dimy, function(error, stdout, stderr){
    //do stuff with stdout
}

Я пробовал использовать setTimeouts и обратные вызовы, но не удалось, но я чувствую, что это происходит, потому что я ссылаюсь на stdout в своем коде, прежде чем он может быть полностью восстановлен. Я тестировал, что stdout на самом деле происходит с потерей данных. Это не асинхронная проблема дальше по линии. Я также тестировал это на своей локальной машине и Heroku, и такая же проблема возникает, каждый раз обрезая один и тот же номер строки.

Любые идеи или предложения относительно того, что может помочь с этим?

Ответ 1

Отредактировано: Я попытался с dir /s на моем компьютере (windows) и получил ту же проблему (это похоже на ошибку), этот код решает эту проблему для меня:

var exec = require('child_process').exec;

function my_exec(command, callback) {
    var proc = exec(command);

    var list = [];
    proc.stdout.setEncoding('utf8');

    proc.stdout.on('data', function (chunk) {
        list.push(chunk);
    });

    proc.stdout.on('end', function () {
        callback(list.join());
    });
}

my_exec('dir /s', function (stdout) {
    console.log(stdout);
})

Ответ 2

У меня были exec.stdout.on('end') обратные вызовы, навешенные навсегда с помощью решения @damphat.

Другим решением является увеличение размера буфера в параметрах exec: см. документацию здесь

{ encoding: 'utf8',
  timeout: 0,
  maxBuffer: 200*1024, //increase here
  killSignal: 'SIGTERM',
  cwd: null,
  env: null }

Чтобы процитировать: maxBuffer указывает наибольший объем данных, разрешенных для stdout или stderr - если это значение превышено, тогда дочерний процесс будет убит. Теперь я использую следующее: это не требует обработки разделенных частей кусков, разделенных запятыми в stdout, в отличие от принятого решения.

exec('dir /b /O-D ^2014*', {
    maxBuffer: 2000 * 1024 //quick fix
    }, function(error, stdout, stderr) {
        list_of_filenames = stdout.split('\r\n'); //adapt to your line ending char
        console.log("Found %s files in the replay folder", list_of_filenames.length)
    }
);

Ответ 3

Реальное (и лучшее) решение этой проблемы заключается в использовании spawn вместо exec. Как указано в этой статье, spawn больше подходит для обработки больших объемов данных:

child_process.exec возвращает весь вывод буфера из дочернего процесса. По умолчанию размер буфера устанавливается равным 200k. Если дочерний процесс возвращает что-то большее, программа запускается с сообщением об ошибке "Ошибка: maxBuffer превышен". Вы можете исправить эту проблему, установив более большой размер буфера в параметрах exec. Но вы не должны этого делать, потому что exec не предназначен для процессов, возвращающих HUGE-буферы на Node. Для этого вы должны использовать spawn. Итак, для чего вы используете exec? Используйте его для запуска программ, которые возвращают состояния результатов, а не данные.

spawn требует другого синтаксиса, чем exec:

var proc = spawn('sh', ['target/bin/solver', 'fields.dimx', 'fields.dimy']);

proc.on("exit", function(exitCode) {
    console.log('process exited with code ' + exitCode);
});

proc.stdout.on("data", function(chunk) {
    console.log('received chunk ' + chunk);
});

proc.stdout.on("end", function() {
    console.log("finished collecting data chunks from stdout");
});