web-dev-qa-db-ja.com

Node.jsのstdoutchild_processexecが短くなりました

Node.jsでは、child_processモジュールのexecコマンドを使用して、Javaで大量のテキストを標準出力に返し、解析して使用するアルゴリズムを呼び出しています。ほとんどキャプチャできますが、一定の行数を超えるとコンテンツがカットオフされます。

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

SetTimeoutsとコールバックを使用しようとしましたが、成功しませんでしたが、完全に取得する前にコードでstdoutを参照しているため、これが発生していると感じています。 stdoutが実際にデータ損失が最初に発生する場所であることをテストしました。これは、今後の非同期の問題ではありません。ローカルマシンとHerokuでもこれをテストしましたが、まったく同じ問題が発生し、毎回まったく同じ行番号で切り捨てられます。

これに何が役立つかについてのアイデアや提案はありますか?

12
Alex H Hadik

編集:コンピューター(windows)でdir /sを試してみましたが、同じ問題が発生しました(バグのように見えます)。このコードで問題を解決できます。

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);
})
4
damphat

@damphatソリューションでexec.stdout.on( 'end')コールバックが永久にハングしました。

別の解決策は、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)
    }
);
10
olamotte

この問題の本当の(そして最良の)解決策は、execの代わりにspawnを使用することです。述べたように この記事で 、スポーンは大量のデータを処理するのにより適しています:

child_process.execは、子プロセスからのバッファ出力全体を返します。デフォルトでは、バッファサイズは200kに設定されています。子プロセスがそれ以上のものを返す場合、プログラムは「エラー:maxBufferを超えました」というエラーメッセージでクラッシュします。 execオプションでより大きなバッファサイズを設定することで、この問題を修正できます。ただし、execは巨大なバッファをノードに返すプロセスを対象としていないため、これを行うべきではありません。そのためには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");
});
8
igelineau