Node.jsからコマンドを別プロセスとして実行

Node.jsアプリケーションから別プロセスを実行する方法です。 今回はNode.jsアプリケーションからあるコマンドラインツールを実行してみます。実行されたコマンドラインツールはメインアプリケーションのプロセスから切り離され、別プロセスとして動きます。

目次

サンプルコード

メインアプリケーション

コマンドラインツールを外部プロセスとして実行するロジック:

//
// app.js
// 
const { spawn } = require('child_process');

// 実行したい外部コマンド: (tick.logへ10回ログ出力します)
const commandline = "node cli/tick.js --times=10 --logfile=tick.log";
runCommand(commandline);

/** コマンドを外部プロセスとして実行 */
function runCommand(command) {
  console.log("running commandline: %s", commandline);
  const parts = commandline.split(" ");
  const cmd = parts[0];
  const args = parts.splice(1);

  // バックグラウンドで実行:
  // メインプロセスが終了しても外部プロセスとして動作します。
  const child = spawn(cmd, args, {
    stdio: 'ignore', // piping all stdio to /dev/null
    detached: true, // メインプロセスから切り離す設定
    env: process.env, // NODE_ENV を tick.js へ与えるため
  });
  child.unref(); // メインプロセスから切り離す
}

上記のコードは、node cli/tick.js --times=3 --logfile=tick.log というコマンドを外部プロセスとして実行するメインプロセスです。

cli/tick.jsはテキトーなログをファイルへ数回出力するだけの簡単なサンプルnodeアプリケーションです。メインプロセスから実行される外部プロセスです。コードは次の通り:

外部コマンドラインツール

//
// cli/tick.js
// 
// ログをn回出力するだけの簡単なcliツール
// Usage: $ node cli/tick.js --times=3 --logfile=tick.log
// 
const fs = require('fs');
const argv = require('minimist')(process.argv.slice(2));

let { times, logfile } = argv;
if (!times) times = 10;
if (!logfile) logfile = './tick.log';


// 標準出力をログファイルへ出力:
const logstream = fs.createWriteStream(logfile, { flags: 'a' });
console.log = function(d) {
  logstream.write(new Date().toLocaleString() + ': ' + d + '\n');
};

// ティック実行:
let time = 0;
const intervalId = setInterval(() => {
  console.log("tick...");
  time += 1;
  if (time >= times) {
    clearInterval(intervalId);
    console.log("end.");
  }
}, 1000);

実行

メインアプリケーション(app.js)を実行:

## 依存モジュールをインストール:
$ npm install --save minimist
## メインアプリケーションを実行:
$ node app.js
running command: node cli/tick.js --times=10 --logfile=tick.log

ログをチェックしてみます:

$ tail -f ./tick.log
...
2019-11-16 07:41:59: tick...
2019-11-16 07:42:00: tick...
2019-11-16 07:42:01: tick...
2019-11-16 07:42:01: end.

tail コマンドで tick.log を監視してみると、メインアプリケーションのプロセス(app.js)が終了した後も外部プロセス(tick.js)は動き続けたことが分かると思います。

以上

PR:時事ネタチェックの時間節約!
芽萌丸プログラミング部 @programming
プログラミング関連アカウント。Web標準技術を中心に書いていきます。フロントエンドからサーバサイドまで JavaScript だけで済ませたい人たちの集いです。