Node.js API (process) - シグナルイベント
プログラムの外部から終了等の操作をしたい場合、 Unix 系ではシグナルを使用します。
Windows ではシグナルはないのですが、 Node.js ではある程度仮想的に対応してくれます。
今回は Node.js でのシグナル処理について説明します。
シグナルの送信
まずは Node.js でシグナルを送信方法です。送信はグローバルオブジェクトである process の kill メソッドを呼び出します。
process.kill(pid[, signal])
// ID が 8888 のプロセスに対して SIGINT を送信 process.kill(8888, 'SIGINT');このメソッド名は Unix にある kill コマンドから来ています。 signal の引数を省略時には、 kill コマンドのように SIGTERM を送信します。
シグナルの送信がなぜ kill コマンドなのかというと、おそらく外部からシグナルを送る場合、プロセスを終了させるためのものが多いからだと思います。
kill もそうですが、子プロセスの生成を spawn(産卵)、親プロセスが終了したのに終わらないプロセスを zombie(ゾンビ) と生き死にかかわる呼び名が多いです。
なお、 Windows ではシグナルの送信は対応していません。
一応、 SIGINT, SIGTERM, SIGKILL は送れるようになっていますが、 実際に送っているのではなく、単にプロセスを強制終了させます。 また、これら以外のシグナルを送信しようとするとエラーが発生します。
シグナル受信イベント
シグナルを受け取ると process オブジェクトはシグナル名をイベント名としたイベントを発行します。 シグナルのイベントにリスナーを登録することによって、デフォルトの動作を変更することができます。以下の例では SIGINT にリスナーを登録しています。
process.on('SIGINT', () => { console.log('Got SIGINT. '); });SIGINT を受け取るとデフォルトでは終了しますが、リスナーを登録したことによって終了しなくなります。
ただし、後述するように登録できないシグナルや登録してもデフォルトの動作が変わらないシグナルもあります。
終了シグナル
シグナルでポイントになるのが、プロセスの終了のためのシグナルです。 それらのシグナルを以下の表にあげました。シグナル | 値 | 機能 | 説明 |
---|---|---|---|
SIGHUP | 1 | 端末切断(Hang UP) |
端末エミュレーターやコンソールを閉じた場合に発生。 Windows でもコンソールを閉じると発生するが、リスナーを登録しても 10 秒程度で無条件に終了する。 |
SIGINT | 2 | 割り込み(INTerapt) | 一般的にキーボードの Ctrl+C で発生。 キーボードから発信は Windows も対応 |
SIGBREAK | - | 停止 | Windows 用のシグナルで Ctrl+Break で発生 |
SIGKILL | 9 | 強制終了 | リスナーの登録不可 |
SIGTERM | 15 | 終了(TERMinate) | kill コマンドの省略時のデフォルト。 Windows 未対応 |
デフォルトでは Node.js はこれらのシグナルを受信するとプログラムをすぐに終了します。
これは SIGKILL を除いて、リスナーを登録して動作を変更することができます。 ただ、慣習的なものもあるので、対応を含めて個別に紹介していきます。
SIGTERM, SIGKILL
SIGTERM が通常の終了で、 SIGKILL は強制終了です。 kill コマンドのデフォルトは、名前と違って SIGKILL ではなく、 SIGTERM の方になっています。終わる前に後処理をしたいというときにイベントをキャッチします。
process.on('SIGTERM', () => { console.log('Got SIGTERM. '); // 後処理など // : process.exit(128+15); });終了時の終了ステータスには慣習があります。それらについては以前の記事を見て下さい。 なお、SIGTERM を受け取っても終了させないというのはあまりよくありません。 外部から終了する手段をなくすのは危険ですし、そもそも SIGKILL の動作は変更できません。
SIGINT, SIGBREAK
SIGINT は割り込みと言いつつ、基本は終了します。 それも強制終了という扱いなどではなく、簡単なプログラムでは Ctrl+C を通常の終了方法としているものもあります。ただ、 CUI で Ctrl+C を使いたいという時もあるので、 これで終了しないプログラムも結構あります。
SIGBREAK は SIGINT と同じような用途ですが、強制終了の意味合いが強い気がします。 Ctrl+Break はそんなに押すようなキーではないですし、そもそも知らない人も多いので、 そのままにしておいてもいいのではないかとは思います。
process.on('SIGBREAK', () => { console.log('Got SIGBREAK. '); process.exit(1); });
SIGHUP
SIGHUP は端末エミュレーターやコンソールを閉じると発生するイベントです。 通常、端末を切る際にはそこで実行させていたコマンドも終了させます。サーバーなどで端末切っても動かしたいということはありますが、そういうときは nohup コマンドを使うので、 終了しないようにする必要はありません。
使い勝手のために SIGHUP で終わらないようにしてもよいですが、 その場合はオプションを付けて起動した場合のみにしておきます。 デフォルトで終わらないのは、ユーザーが気付かずにプロセスを残す危険性が高くなります。
process.on('SIGHUP', ()=> { console.log('Got SIGHUP. '); // -d オプションが付いていたら、終了しない if (process.argv[2] != '-d') { process.exit(128+1); } });なお、 Windows ではリスナーを登録しても、しばらくすると無条件で終了します。 終了を止めることはできませんし、ここで後処理を入れても完了できる保証はありません。
また、 Unix 系ではデーモンなどのように動かし続け、ユーザーによる起動をあまり想定していないプログラムでは SIGHUP は終了ではなく、設定の再読み込みとして使われます。 ただ、 Node.js でデーモンを作るということはあまり無いかと思います。
その他のシグナル
シグナルというのは、まだまだあるのですが、終了シグナル以外で Node.js のドキュメントで紹介されていたのを紹介します。シグナル | 説明 |
---|---|
SIGUSR1 |
SIGUSR1, SIGUSR2 はプログラム側で自由に使っていいシグナルとして用意されてる。 Node.js ではそのうちの SIGUSR1 をデバッガーが起動に充てている。 リスナーの登録はできるが、デバッガーの起動を止めることはできない |
SIGPIPE | 接続の切れたソケットに書き込みを行うと発生。デフォルトではプロセスの終了。 |
SIGWINCH | コンソールのサイズが変更された場合に発生。 Windows でもカーソルの移動などで送信。 |
SIGSTOP | 一時停止用シグナル。 Node.js では設定不可 |
サンプルコード
今回は先にサンプルコードを紹介します。各ファイルはリンクの [名前を付けて保存] で取得出来ます。送信用のスクリプトです。 引数に プロセス ID とシグナル名を指定して、シグナルを送信します。
$ node process_signal_kill.js 8132 SIGINT
受信側のスクリプトです。 起動すると以下のことを行います。
- プロセス ID を出力
- 5 分待って終了
- 終了時に終了ステータス(Exit Code)を出力
$ node process_signal_rec.js Process ID = 9432ちなみに exit イベントが発生せず、終了ステータスが表示されない場合、 Unit 系では $?、 Windows では %ERRORLEVEL% で表示できます。
また、後述するシグナルイベントの取得例を追加したサンプルも用意しています。 node コマンドの使い方について詳しくは以前の記事をご覧ください。
- 関連記事
-
- Node.js API (events) - イベントシステム
- Node.js API (process) - exit によるプログラムの終了
- Node.js API (process) - シグナルイベント
- Node.js API (url) - URL 文字列の解析と生成
- Node.js API (path) - ファイルパスの文字列操作
Facebook コメント
コメント