1

子プロセスのstdoutを別のstdinとして使用すると、次の子にデータが渡されないことがあります。子プロセスのstdoutを別の子プロセスのstdoutとして使用すると、2番目の子プロセスにデータが渡されない場合がある

var spawn = require('child_process').spawn; 
var pipeId = 0; 

var launchProcess = function(cmd, args, stdin){ 
    return spawn(cmd, args, { 
    stdio: [stdin ? stdin : 'ignore', 'pipe', 'pipe'] 
    }); 
}; 

var launch = function(){ 
    var task0 = launchProcess('echo', ['how\nare\nyou\ndear\nstranger']); 
    var task1 = launchProcess('tee', ['/tmp/body-pipeline-' + pipeId], task0.stdout); 

    pipeId++; 

    task1.on('exit', launch); 
}; 

launch(); 

いくつかのファイルが空である:

ls -lhS /tmp/body-pipeline-* 

私もtask0.stdout._handle.fdにアクセスすることにより、正の整数として、ファイル記述子を渡すと、問題が解決してみました。

私の知る限り、これはシェルパイプの仕組みです。あるプロセスのstdoutと同じファイル記述子が別のプロセスのstdinとして使用されます。子プロセスが大量のデータを出力するときにCPU負荷が高くなるため、NodeJSプロセスですべてのデータを渡すことを避けようとしています。

更新:パイプは、両方の標準入力に使用し、すべてが期待どおりに(長いテキストをテストするために、ここで猫を使用して)動作する標準出力されます。

var spawn = require('child_process').spawn; 
var pipeId = 0; 

var launchProcess = function(cmd, args, stdin){ 
    return spawn(cmd, args, { 
    stdio: [stdin ? stdin : 'pipe', 'pipe', 'pipe'] 
    }); 
}; 

var launch = function(){ 
    var task0 = launchProcess('cat'); 
    var task1 = launchProcess('tee', ['/tmp/body-pipeline-' + pipeId]); 

    task0.stdout.pipe(task1.stdin) 

    task0.stdin.write(JSON.stringify(process.env).split(',').join('\n')) 
    task0.stdin.end(); 

    pipeId++; 

    task1.on('exit', launch); 
}; 

launch(); 

アップデート2task0.stdout.pipe(task1.stdin)を使用している場合、スクリプトは50を使用しています%のCPU(TASK1のSTDINとしてtask0の標準出力を渡すときに0%に比較して):

var spawn = require('child_process').spawn; 
var pipeId = 0; 

var launchProcess = function(cmd, args, stdin, stdout, stderr){ 
    return spawn(cmd, args, { 
    stdio: [stdin, stdout, stderr] 
    }); 
}; 

var launch = function(){ 
    var task0 = launchProcess('yes', ['lala'], 'ignore', 'pipe', 'ignore'); 
    var task1 = launchProcess('tee', ['/tmp/body-pipeline-' + pipeId], 'pipe', 'ignore', 'ignore'); 
    // var task1 = launchProcess('tee', ['/tmp/body-pipeline-' + pipeId], task0.stdout, 'ignore', 'ignore'); 


    task0.stdout.pipe(task1.stdin); 

    pipeId++; 

    task1.on('exit', launch); 
}; 

launch(); 

Update3と:これは私の問題をよく説明しています。私は元のコードでそれを単純化しようとしましたが、あまりに単純化されたと思います。ラリーTurtisは簡略化された場合の回避策を提供したが、それは私のものには適用されません:あなたが終了する2番目のプロセスを待たない場合

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

var pipeId = 0; 
var pipeSlots = 6; 

var launchProcess = function(cmd, args, stdin, stdout){ 
    return spawn(cmd, args, { 
    stdio: [stdin, stdout, 'ignore'] 
    }); 
}; 

var launch = function(){ 
    var task0 = launchProcess('echo', ['how\nare\nyou\ndear\nstranger'], 'ignore', 'pipe'); 
    var task1 = launchProcess('tee', ['/tmp/body-pipeline-' + pipeId], task0.stdout, 'ignore'); 

    task0.on('error', function(err){ 
    console.log('Error while processing task0:' + err.stack); 
    }); 
    task1.on('error', function(err){ 
    console.log('Error while processing task1:' + err.stack); 
    }); 

    pipeId++; 
}; 

// Simulating message queue 
setInterval(function(){ 
    // Simulating how many messages we get from the messaging queue 
    var mqMessageCount = Math.floor(Math.random() * (pipeSlots + 1)); 

    for(var i = 0; i < mqMessageCount; i++){ 
    launch(); 
    } 
}, 250); // For this test we assume that pipes finish under 250ms 
+0

ヒント:ほとんどの場合、前者はstdout/stderrで利用できるデータがないことを示すので、子プロセスの '' close''イベントを '' exit''の代わりに使用するべきです。 '' close'''は常に '' exit''の後に来ます。 – mscdex

+0

@mscdex情報をありがとうございます!新しいプロセスの起動は、他の起動プロセスが実行中であるか、終了しているかによって異なる動作をすべきではありません。 –

答えて

0

これは、現在知られているNodeJS問題です:https://github.com/nodejs/node/issues/9413

TLDR。私の同僚はこれを修正した素晴らしいアイデアを持っていました:

var task1 = launchProcess('tee', ['/tmp/body-pipeline-' + pipeId], 'pipe', 'ignore'); 
var task0 = launchProcess('echo', ['how\nare\nyou\ndear\nstranger'], 'ignore', task1.stdin); 

送信タスクを開始する前に受信タスクを起動することです。

0

あなたの元のコードは正常に動作します。

var launch = function(){ 
    var task0 = launchProcess('echo', ['how\nare\nyou\ndear\nstranger']); 
    var task1 = launchProcess('tee', ['/tmp/body-pipeline-' + pipeId], task0.stdout); 

    pipeId++; 

    launch(); 
}; 

起こっているのは、タスク1が実行されている可能性がありますが、タスク0はそうではありません。それはなぜ私にとって100%明確ではないのですが、それは明らかです。問題を解決する両方のタスクを確保

..when the 'exit' event is triggered, child process stdio streams might still be open.

が完了している:おそらくノードdocumentationに我々がいることに注意しているという事実に関連します。

var spawn = require('child_process').spawn; 
var q = require("q"); 
var pipeId = 0; 

var launchProcess = function(cmd, args, stdin) { 
    return spawn(cmd, args, { 
     stdio: [stdin ? stdin : 'ignore', 'pipe', 'pipe'] 
    }); 
}; 

var launch = function() { 
    var task0 = launchProcess('echo', ['how\nare\nyou\ndear\nstranger']); 
    var task1 = launchProcess('tee', ['/tmp/body-pipeline-' + pipeId], task0.stdout); 

    var p0 = q.defer(); 
    var p1 = q.defer(); 
    task0.on('exit', p0.resolve); 
    task1.on('exit',p1.resolve); 

    q.all(p0, p1).then(launch) 

    pipeId++; 
}; 

launch(); 
+0

2つの異なる機能がプロセスを起動する必要がある場合、干渉がないはずなので、これはNodeJSのバグ(またはAPIの誤用)のようです。私の場合、6つのパイプラインスロット(12のタスク)があるので、常に子プロセスを実行しており、パイプを順番に実行することはできません。 –

関連する問題