Node.js v0.11.11 マニュアル & ドキュメンテーション


Child Process#

Stability: 3 - Stable

Nodeは child_process モジュールを通じて、3 方向の popen(3) 機能を提供します。

これは完全にノンブロッキングな方法で子プロセスの stdinstdout、 そして stderr を通じたデータストリームを実現します。 (いくつかのプログラムは内部的にバッファリングされた I/O を使うことに 注意してください。それは node.js には影響しませんが、 子プロセスに送ったデータがすぐに消費されるとは限らないことを意味します)。

子プロセスの生成は require('child_process').spawn() または require('child_process').fork() を使います。 それぞれの意味論は以下で説明するようにわずかに異なります。

Class: ChildProcess#

ChildProcessEventEmitter です。

子プロセスは常に 3 本のストリームと関連づけられています。 child.stdinchild.stdout、そして child.stderr です。 それらは親プロセスの標準入出力ストリームを共有するかもしれませんし、 独立したストリームオブジェクトにパイプでつながれているかもしれません。

Event: 'error'#

  • err {Error Object} エラー。

次の場合に生成されます:

  1. プロセスを起動できなかった、または
  2. プロセスを殺すことができなかった、または
  3. 何らかの理由で子プロセスにメッセージを送信することが失敗した。

エラーが発生した後、'exit' イベントは生成されることもあれば されないこともあることに注意してください。 もし両方のイベントを監視するなら、リスナ関数は2回呼び出されることに備えることを 忘れないでください。

ChildProcess#kill() および ChildProcess#send() も参照してください。

Event: 'exit'#

  • code {Number} 通常に終了した場合は終了コード。
  • signal {String} 親プロセスによって終了させられた場合は、 子プロセスを終了するために送られたシグナル。

このイベントは子プロセスが終了した後で生成されます。 プロセスが普通に終了した場合、code はプロセスの終了コードです。 それ以外の場合は null です。 プロセスがシグナルを受け取って終了した場合、signal は文字列によるシグナルの名前です。 それ以外の場合は null です。

子プロセスの標準入出力ストリームはオープンしたままになっているかも しれないことに注意してください。

また、Node が 'SIGINT' および 'SIGTERM' に対するシグナルハンドラを 確立するため、子プロセスがそれらのシグナルを受けとって終了しても、 signal` にはそれらのシグナルの名前が設定されないことに注意してください。

waitpid(2) を参照してください。

Event: 'close'#

  • code {Number} 普通に終了した場合は、その終了コード。
  • signal {String} 親プロセスによって殺された場合は、 子プロセスを殺すために渡されたシグナル。

このイベントは、子プロセスの標準入出力ストリームが全て終了した場合に 生成されます。 複数のプロセスが同じ標準入出力ストリームを共有するかもしれないので、 これは 'exit' とは明確に異なります。

Event: 'disconnect'#

このイベントは、親プロセスまたは子プロセスで .disconnect() メソッドが 呼び出された場合に生成されます。 切断の後では、プロセス間でメッセージを送信することはできず、 .connected プロパティは false になります。

Event: 'message'#

  • message {Object} 解析済みの JSON オブジェクトまたはプリミティブ値
  • sendHandle {Handle object} ソケットまたはサーバオブジェクト

.send(message, [sendHandle]) によって送信されたメッセージは 'message' イベントによって取得できます。

child.stdin#

  • Stream object

子プロセスの stdin を表現する Writable Stream です。 多くの場合、end() を通じてこのストリームを閉じると子プロセスが終了する原因となります。

子プロセスの標準入出力が親プロセスと共有されている場合は設定されません。

child.stdout#

  • Stream object

子プロセスの stdout を表現する Readable Stream です。

子プロセスの標準入出力が親プロセスと共有されている場合は設定されません。

child.stderr#

  • Stream object

子プロセスの stderr を表現する Readable Stream です。

子プロセスの標準入出力が親プロセスと共有されている場合は設定されません。

child.pid#

  • Integer

子プロセスの PID です。

例:

var spawn = require('child_process').spawn,
    grep  = spawn('grep', ['ssh']);

console.log('Spawned child pid: ' + grep.pid);
grep.stdin.end();

child.connected#

  • {Boolean} .disconnect' が呼び出されると false` に設定される

.connectedfalse の場合、メッセージを送信することはできません。

child.kill([signal])#

  • signal String

子プロセスにシグナルを送ります。 引数が与えられない場合、子プロセスには 'SIGTERM' が送られます。 利用可能なシグナルの一覧は signal(7) を参照してください。

var spawn = require('child_process').spawn,
    grep  = spawn('grep', ['ssh']);

grep.on('close', function (code, signal) {
  console.log('child process terminated due to receipt of signal '+signal);
});

// send SIGHUP to process
grep.kill('SIGHUP');

シグナルを送ることができなかった場合は 'error' イベントが 生成されるかもしれません。 既に終了した子プロセスへシグナルを送信してもエラーにはならず、 予想しない結果になるかもしれません: PID (プロセス ID) が他のプロセスに再割り当てされると、 シグナルはそのプロセスに送信されてしまいます。 それで何が起こるかは誰にも予想できません。

この関数は kill と呼ばれるものの、 子プロセスに届けられるシグナルが実際には子プロセスを殺さないかもしれないことに注意してください。 kill はただプロセスにシグナルを送るだけです。

kill(2) を参照してください。

child.send(message, [sendHandle])#

  • message Object
  • sendHandle Handle object

child_process.fork() を使うと、child.send(message, [sendHandle]) を 使って子プロセスにメッセージを送信し、子プロセスではそれを 'message' イベントによって受け取ることができます。

例:

var cp = require('child_process');

var n = cp.fork(__dirname + '/sub.js');

n.on('message', function(m) {
  console.log('PARENT got message:', m);
});

n.send({ hello: 'world' });

子プロセスの 'sub.js' は次のようになります:

process.on('message', function(m) {
  console.log('CHILD got message:', m);
});

process.send({ foo: 'bar' });

子プロセスでは process オブジェクトは send() メソッドを持ち、 そのチャネル上でメッセージを受信するたびにイベントを生成します。

親プロセスと子プロセスのいずれにおいても、send() メソッドは同期的です - データの大きな塊を送信することは推奨されません (代わりにパイプを使うことが出来ます、 child_process.spawn を参照してください)。

特別なケースとして、{cmd: 'NODE_foo'} のようなメッセージを 送信する場合があります。 cmd プロパティが接頭辞 NODE_ を含む全てのメッセージは node のコアで 使われる内部的なメッセージであるため、'message' イベントを生成しません。 この接頭辞を含むメッセージは 'internalMessage' イベントを生成しますが、 それを使用すべきではありません。それは保証なしに変更される可能性があります。

child.send()sendHandle オプションは TCP サーバまたは ソケットオブジェクトを他のプロセスに送信するためのものです。 子プロセスはそれを 'message' イベントの第 2 引数として受信します。

たとえば子プロセスが既に終了した場合など、メッセージを送信できなかった場合は 'error' イベントが生成されます。

Example: sending server object#

サーバを送信する例:

var child = require('child_process').fork('child.js');

// Open up the server object and send the handle.
var server = require('net').createServer();
server.on('connection', function (socket) {
  socket.end('handled by parent');
});
server.listen(1337, function() {
  child.send('server', server);
});

サーバオブジェクトを受信する子プロセス:

process.on('message', function(m, server) {
  if (m === 'server') {
    server.on('connection', function (socket) {
      socket.end('handled by child');
    });
  }
});

サーバは親プロセスと子プロセスで共有されることに注意してください。 これはコネクションが時には親あるいは子で処理されることを意味します。

dgram サーバのワークフローも同じです。 connection イベントの代わりに message イベントを監視し、 server.listen の代わりに server.bind を使用してください (現時点では UNIX プラットフォームでのみサポートされています)。

Example: sending socket object#

これはソケットを送信する例です。 これは二つの子プロセスを起動し、コネクションのリモートアドレスが VIP (74.125.127.100) ならソケットを "special" 子プロセスに送信します。 その他のソケットは "normal" プロセスに送られます。

var normal = require('child_process').fork('child.js', ['normal']);
var special = require('child_process').fork('child.js', ['special']);

// Open up the server and send sockets to child
var server = require('net').createServer();
server.on('connection', function (socket) {

  // if this is a VIP
  if (socket.remoteAddress === '74.125.127.100') {
    special.send('socket', socket);
    return;
  }
  // just the usual dudes
  normal.send('socket', socket);
});
server.listen(1337);

chold.js は次のようになります:

process.on('message', function(m, socket) {
  if (m === 'socket') {
    socket.end('You were handled as a ' + process.argv[2] + ' person');
  }
});

一度ソケットが子プロセスに送信されると、親プロセスはもうソケットがいつ 破棄されるか知ることができないことに注意してください。 この状態を示すために,.connections プロパティは null になります。 この状態では、.maxConnections も使わないことを推奨します。

child.disconnect()#

親プロセスと子プロセス間の IPC コネクションをクローズし、 他の接続を持たない子プロセスが自然に終了することを可能にします。 このメソッドを呼び出すと、親プロセスと子プロセスの両方で .connectedfalse に設定され、メッセージを送信することはできなくなります。

プロセスが受信するメッセージがなければ、おそらくはすぐに 'disconnect' イベントが生成されます。

子プロセスでも process.disconnect() を呼び出せることに注意してください。

child_process.spawn(command, [args], [options])#

  • command {String} 実行するコマンド
  • args {Array} 文字列による引数の配列
  • options {Object}
    • cwd {String} 子プロセスのカレントワーキングディレクトリ
    • stdio {Array|String} 子プロセスの標準入出力の設定 (後述)。
    • customFds {Array} Deprecated 子プロセスが標準入出力として使用する ファイル記述子の配列 (後述)
    • env {Object} 環境変数として与えるキー・値のペア
    • detached {Boolean} 子プロセスがプロセスグループのリーダになるかどうか (後述)。
    • uid {Number} このプロセスのユーザ識別子を設定します (setuid(2) を参照)。
    • gid {Number} このプロセスのグループ識別子を設定します (setgid(2) を参照)。
  • return: {ChildProcess object}

args をコマンドライン引数として、与えられた command で新しいプロセスを起動します。 args が省略された場合、空の配列がデフォルトとなります。

第 3 引数は追加のオプションを指定するために使われ、そのデフォルトは:

{ cwd: undefined,
  env: process.env
}

cwd で起動されたプロセスのワーキングディレクトリを指定することができます。 env は新しいプロセスに見える環境変数を指定するために使います。

ls -lh /usr を実行して stdoutstderr、および終了コードを取得する例:

var spawn = require('child_process').spawn,
    ls    = spawn('ls', ['-lh', '/usr']);

ls.stdout.on('data', function (data) {
  console.log('stdout: ' + data);
});

ls.stderr.on('data', function (data) {
  console.log('stderr: ' + data);
});

ls.on('close', function (code) {
  console.log('child process exited with code ' + code);
});

とても手の込んだ方法で実行する 'ps ax | grep ssh' の例:

var spawn = require('child_process').spawn,
    ps    = spawn('ps', ['ax']),
    grep  = spawn('grep', ['ssh']);

ps.stdout.on('data', function (data) {
  grep.stdin.write(data);
});

ps.stderr.on('data', function (data) {
  console.log('ps stderr: ' + data);
});

ps.on('close', function (code) {
  if (code !== 0) {
    console.log('ps process exited with code ' + code);
  }
  grep.stdin.end();
});

grep.stdout.on('data', function (data) {
  console.log('' + data);
});

grep.stderr.on('data', function (data) {
  console.log('grep stderr: ' + data);
});

grep.on('close', function (code) {
  if (code !== 0) {
    console.log('grep process exited with code ' + code);
  }
});

exec の失敗をチェックする例:

var spawn = require('child_process').spawn,
    child = spawn('bad_command');

child.stderr.setEncoding('utf8');
child.stderr.on('data', function (data) {
  if (/^execvp\(\)/.test(data)) {
    console.log('Failed to start child process.');
  }
});

spawn() は空の options オブジェクトを受け取ると、 process.env を使うのではなく,空の環境変数で子プロセスを起動します。 これは廃止された API との互換性のためです。

child_process.spawn()stdio オプションは配列で、 それぞれのインデックスは子プロセスの fd に対応します。 要素の値は以下のいずれかです:

  1. 'pipe' - 子プロセスと親プロセスの間でパイプを作成します。 パイプの親側の端点は child_process オブジェクトのプロパティ ChildProcess.stdio[fd] として親プロセスに公開されます。 fd 0~2 はそれぞれ、ChildProcess.stdinChildProcess.stdoutChildProcess.stderr としても参照可能です。
  2. 'ipc' - 親プロセスと子プロセスの間でメッセージパッシングのための IPC チャネル/ファイル記述子を作成します。 ChildProcess は標準入出力に高々一つの IPC ファイル記述子を持ちます。 このオプションを設定すると、ChildProcess.send() メソッドが有効になります。 子プロセスがこのファイル記述子に JSON メッセージを書き込むと、 それは ChildProcess.on('message') を引き起こします。 子プロセスが Node.js プログラムなら、IPC チャネルの存在は process.send() および process.on('message') を有効にします。
  3. 'ignore' - 子プロセスにファイル記述子を設定しません。 Node は子プロセスを起動する際、常に fd 0~2 をオープンすることに 注意してください。これらのうちのどれかが 'ignore' の場合、node は /dev/null をオープンして、それを子プロセスの fd に割り当てます。
  4. Stream オブジェクト - tty、ファイル、ソケット、またはパイプを参照する 読み込みまたは書き込み可能なストリームを子プロセスと共有します。 ストリームの下層にあるファイル記述子は、子プロセスの stdio 配列の 対応する位置にコピーされます。 ストリームは下層のファイル記述を持っていなければならないことに 注意してください (ファイルストリームは 'open' イベントが発生するまで それを持ちません)。
  5. 非負整数 - 整数の値を親プロセスが現在オープンしているファイル記述子として 解釈されます。 それは Stream オブジェクトの場合と同様に子プロセスに共有されます。
  6. nullundefined - デフォルト値を使用します。 stdiofd が 0、1、または 2 (言い換えると stdin、stdout、または stderr) の場合はパイプが作成されます。fd が 3 以上の場合、デフォルトは 'ignore' です。

簡易な記法として、stdio に配列ではなく以下の文字列の一つを指定することも できます。

  • ignore - ['ignore', 'ignore', 'ignore']
  • pipe - ['pipe', 'pipe', 'pipe']
  • inherit - [process.stdin, process.stdout, process.stderr] または [0,1,2]

例:

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

// Child will use parent's stdios
spawn('prg', [], { stdio: 'inherit' });

// Spawn child sharing only stderr
spawn('prg', [], { stdio: ['pipe', 'pipe', process.stderr] });

// Open an extra fd=4, to interact with programs present a
// startd-style interface.
spawn('prg', [], { stdio: ['pipe', null, null, null, 'pipe'] });

detached オプションが設定されると、子プロセスは新しいプロセスグループの リーダになります。 これは親プロセスが終了しても子プロセスの実行が継続することを可能にします。

デフォルトでは、親プロセスは切り離された子プロセスの終了を待機します。 親プロセスが child を待機することを防ぐには、child.unref() メソッドを 使用し、親のイベントループに子のリファレンスカウントが含まれないようにします。

長時間実行する子プロセスを切り離し、出力をファイルにリダイレクトする例:

 var fs = require('fs'),
     spawn = require('child_process').spawn,
     out = fs.openSync('./out.log', 'a'),
     err = fs.openSync('./out.log', 'a');

 var child = spawn('prg', [], {
   detached: true,
   stdio: [ 'ignore', out, err ]
 });

 child.unref();

長時間実行されるプロセスを開始するために detached オプションを使用する場合、 その stdio が親と接続するような構成を与えられない限り、そのプロセスは バックグラウンドにとどまりません。 親の stdio が継承されるなら、子プロセスは制御しているターミナルに 接続されたままです。

指定のファイル記述子を子プロセスの標準入出力に指定することを可能にする、 customFds と呼ばれる廃止されたオプションがありました。 この API は全てのプラットフォームに移植可能ではないために削除されました。 customFds は新しいプロセスの [stdin, stdout, stderr] を既存のストリームに接続することを可能にしました; -1 は新しいストリームが作られなければならないことを意味していました。 使用する場合は自己責任で。

関連項目: child_process.exec() および child_process.fork()

child_process.exec(command, [options], callback)#

  • command {String} 実行するコマンド、空白で区切られた引数を持ちます
  • options {Object}
    • cwd {String} 子プロセスのカレントワーキングディレクトリ
    • env {Object} 環境変数として与えるキー・値のペア
    • encoding {String} (Default: 'utf8')
    • shell {String} コマンドを実行するシェル (デフォルト: UNIX では 'bin/sh'、Windows では 'cmd.exe'。 シェルは UNIX では -c スイッチを、 Windows では /s /c を理解すべきです。 Windows では、コマンドラインの解析は cmd.exe と互換であるべきです)。
    • timeout {Number} (Default: 0)
    • maxBuffer {Number} (Default: 200*1024)
    • killSignal {String} (Default: 'SIGTERM')
  • callback {Function} プロセスが終了するとその出力を伴って呼び出されます
    • error {Error}
    • stdout {Buffer}
    • stderr {Buffer}
  • Return: ChildProcess object

コマンドをシェルで実行し、その出力をバッファに格納します。

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

child = exec('cat *.js bad_file | wc -l',
  function (error, stdout, stderr) {
    console.log('stdout: ' + stdout);
    console.log('stderr: ' + stderr);
    if (error !== null) {
      console.log('exec error: ' + error);
    }
});

コールバックは引数 (error, stdout, stderr) を得ます。 成功すると、errornull になります。 エラーだと、errorError のインスタンスとなり、 err.code は子プロセスの終了コード、 err.signal はプロセスを終了させたシグナルとなります。

任意の第 2 引数でいくつかのオプションを指定することができます。 オプションのデフォルトは

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

もし timeout が 0 より大きいと、 子プロセスは実行時間が timeout ミリ秒よりも長くなると kill されます。 子プロセスは killSignal で kill されます (デフォルト: 'SIGTERM')。 maxBuffer は標準出力と標準エラーの最大のデータ量を指定します - この値を超えると子プロセスは kill されます。

child_process.execFile(file, [args], [options], [callback])#

  • file {String} 実行するプログラムのファイル名
  • args {Array} 文字列による引数の配列
  • options {Object}
    • cwd {String} 子プロセスのカレントワーキングディレクトリ
    • env {Object} 環境変数として与えるキー・値のペア
    • encoding {String} (Default: 'utf8')
    • timeout {Number} (Default: 0)
    • maxBuffer {Number} (Default: 200*1024)
    • killSignal {String} (Default: 'SIGTERM')
  • callback {Function} プロセスが終了するとその出力を伴って呼び出されます
    • error {Error}
    • stdout {Buffer}
    • stderr {Buffer}
  • Return: ChildProcess object

子シェルで実行する代わりに指定されたファイルを直接実行することを除いて child_process.exec() と同様です。 これは child_process.exec より若干効率的で、同じオプションを持ちます。

child_process.fork(modulePath, [args], [options])#

  • modulePath {String} 子プロセスで実行するモジュール
  • args {Array} 文字列による引数の配列
  • options {Object}
    • cwd {String} 子プロセスのカレントワーキングディレクトリ
    • env {Object} 環境変数として与えるキー・値のペア
    • encoding {String} (デフォルト: 'utf8')
    • execPath {String} 子プロセスの作成に使われる実行ファイル
    • execArgv {Array} 実行ファイルに渡される引数を表す文字列の配列 (デフォルトは process.execArgv)。
    • silent {Boolean} true の場合、子プロセスの標準入力、標準出力、 標準エラー出力は親プロセスにパイプされます。 そうでない場合は親プロセスから継承します。 より詳細は spawn()pipe および inherit オプションを参照してください (デフォルトは false)。
  • Return: ChildProcess object

これは spawn() の特別版で、Node プロセスを起動します。 返されるオブジェクトは通常の ChildProcess の全てのメソッドに加えて、 組み込みの通信チャネルを持ちます。 詳細は child.send(message, [sendHandle]) を参照してください。

これらの子 Node は、やはり V8 の新しいインスタンスです。 新しい Node ごとに少なくとも 30 ミリ秒の起動時間と 10MB のメモリを前提としてください。 つまり、数千の子プロセスを作ることは出来ません。

options オブジェクト中の execPath プロパティは、 現在の node 実行ファイルではない子プロセスの作成を可能にします。 デフォルトでは、子プロセスの環境変数 NODE_CHANNEL_FD によって示される ファイル記述子を通じて対話することに注意しなければなりません。 このファイル記述子における入力と出力は、改行で区切られた JSON オブジェクトです。