NodeJSプロセスがどのように終了するかについて詳しく説明します

NodeJSプロセスがどのように終了するかについて詳しく説明します

序文

NodeJS プロセスが終了する原因はいくつかあります。これらの要因には、コードが例外をスローするなど予防可能なものもあれば、メモリ不足など予防不可能なものもあります。グローバル変数 process は、イベント エミッター インスタンスです。プロセスが正常に終了すると、プロセスは終了イベントをディスパッチします。アプリケーション コードはこのイベントをリッスンして最終的なクリーンアップを実行できます。

次の表に、プロセスが終了する原因となる要因を示します。

操作する
手動終了プロセス終了(1)
キャッチされない例外新しいエラーをスローします()
未処理の約束の拒否Promise.reject()
未処理のエラーイベントイベントエミッター#emit('error')
未処理信号<プロセスID> を強制終了する

積極的な撤退

process.exit(code) はプロセスを終了する最も直接的な方法です。コード パラメータはオプションで、0 ~ 255 の任意の数値を指定できます。デフォルト値は 0 です。0 はプロセスが正常に実行されたことを示し、0 以外の数値はプロセスが失敗したことを示します。

process.exit() を使用すると、コンソールに出力されません。プロセスが終了したときにコンソールにエラー情報を出力したい場合は、呼び出す前にエラー情報を表示する必要があります。

ノード -e "プロセス終了(42)"
$をエコーし​​ますか?

上記のコードは NodeJS プロセスを直接終了し、コマンド ラインに出力情報はありません。プロセスが終了すると、ユーザーは有効なエラー情報を取得できません。

関数 checkConfig(config) {
  if (!config.host) {
    console.error("構成に 'host' パラメータがありません!");
    プロセス終了(1);
  }
}

上記のコードでは、プロセスが終了する前に明確なエラー メッセージを出力します。

process.exit() は非常に強力ですが、ユーティリティ ライブラリでは使用しないでください。ツール ライブラリでエラーが発生した場合は、それを例外としてスローし、アプリケーション コードでエラーの処理方法を決定できるようにする必要があります。

例外、拒否、および発行されたエラー

process.exit() は、アプリケーションの起動構成チェックなどのシナリオでは非常に便利ですが、実行時例外の処理には適していないため、他のツールが必要です。

たとえば、アプリケーションが HTTP リクエストを処理しているときに、エラーによってプロセスが終了するのではなく、エラー メッセージを含む応答を返す必要があります。

Error クラスには、呼び出しスタックやエラー テキストなど、発生したエラーの詳細を説明するデータを含めることができます。通常、特定のシナリオに対して XXXError を定義し、これらの XXXError はすべて Error クラスを継承します。

throw キーワードを使用するとき、またはコード ロジックにエラーがある場合、エラーがスローされます。この時点で、システム コール スタックが解除され、現在の呼び出しをラップする try/catch ステートメントが検出されるまで、各関数は終了します。 try/catch ステートメントがない場合、エラーはキャッチされない例外と見なされます。

通常、NodeJS アプリケーションでは、特定のエラーを説明するエラー コードとして、Error クラスの code プロパティを定義します。これを行う利点は、エラー コードを一意かつ読みやすい状態に保つことができることです。同時に、メッセージ属性を使用して特定のエラー情報を記述することもできます。

キャッチされない例外がスローされると、コール スタックがコンソールに出力され、プロセスは終了ステータス 1 で終了します。

/tmp/foo.js:1
新しい TypeError をスローします ('無効な foo')。
^
エラー: 無効な foo
    Object.<anonymous> (/tmp/foo.js:2:11) で
    ... 省略されました ...
    internal/main/run_main_module.js:17:47 で

このコンソール出力は、foo.js の 2 行目、11 列目でエラーが発生したことを示しています。

グローバル変数 process は、uncaughtException イベントをリッスンしてこれらのキャッチされていない例外を処理できるイベント エミッター インスタンスです。次のコードはその使用方法を示しています。

logger は、次のコードで定義されます。
process.on("uncaughtException", (エラー) => {
  logger.send("キャッチされない例外が発生しました", error, () => {
    コンソールエラー(エラー);
    プロセス終了(1);
  });
});

Promise Rejection は例外をスローすることに似ています。拒否() 関数を呼び出すか、非同期関数で例外をスローすることで、Promise を拒否状態に到達させることができます。次の 2 つのコード スニペットは同様の機能を持ちます。

Promise.reject(new Error("ああ、だめだ"));

(非同期() => {
  新しいエラーをスローします("ああ、だめだ");
})();

現在、NodeJS 14 では、Promise Rejection によってプロセスが終了しません。以降のバージョンでは、Promise Rejection によってプロセスが終了する可能性があります。

以下は、キャッチされていない Promise 拒否のコンソール出力のサンプルです。

(ノード:52298) UnhandledPromiseRejectionWarning: エラー: ああ、だめだ
Object.<anonymous> (/tmp/reject.js:1:16) で
... 省略されました ...
internal/main/run_main_module.js:17:47 で
(ノード:52298) UnhandledPromiseRejectionWarning: 処理されていないプロミス
このエラーは、
catchブロックなしの非同期関数、またはpromiseを拒否する
これは .catch() では処理されませんでした。

unhandledRejection イベントをリッスンすることで、キャッチされていない拒否を処理できます。サンプル コードは次のとおりです。

process.on("unhandledRejection", (reason, promise) => {});

Event Emitter は NodeJS の基本モジュールであり、広く使用されています。イベント エミッターのエラー イベントが処理されない場合、イベント エミッターはエラーをスローし、プロセスを終了します。以下は、イベント エミッター エラーのコンソール出力です。

イベント.js:306
throw err; // 処理されない「エラー」イベント
^
エラー [ERR_UNHANDLED_ERROR]: 処理されないエラーです。(未定義)
EventEmitter.emit (events.js:304:17) で
Object.<anonymous> (/tmp/foo.js:1:40) で
... 省略されました ...
internal/main/run_main_module.js:17:47 {で
コード: 'ERR_UNHANDLED_ERROR'、
コンテキスト: 未定義
}

したがって、Event Emitter を使用する場合は、エラーが発生したときにアプリケーションがこれらのエラーを処理してクラッシュを回避できるように、エラー イベントをリッスンする必要があります。

信号

シグナルは、プロセス間通信のメカニズムを提供する操作メッセージです。信号は通常は数値ですが、文字列で識別することもできます。たとえば、SIGKILL は数字 9 を識別します。オペレーティング システムによって信号の定義が異なります。次の表に、基本的な共通信号の定義を示します。

名前番号処理可能ですか? NodeJS のデフォルトの動作信号が意味するもの
SIGHUP 1はいやめる親コマンドラインは閉じられています
シギント2はいやめるコマンドラインから中断してみてください(Ctrl+C)
終了3はいやめるCtrl + Zを押してコマンドラインを終了してください
シグナルキル9いいえやめるプロセスを強制終了する
SIGUSR1 10はいデバッガーを起動するユーザー定義信号
SIGUSR2 12はいやめるユーザー定義信号
シグナルターム15はいやめるプロセスは正常に終了する
シグナルストップ19いいえやめるプロセスは強制的に停止されました

この表では、信号が処理可能かどうかは、プロセスによって信号を受信して​​処理できるかどうかを示します。 NodeJS のデフォルトの動作は、このシグナルを受信した後にプロセスが実行するデフォルトのアクションを示します。

これらの信号は次の方法で監視できます。

#!/usr/bin/env ノード
console.log(`プロセスID: ${process.pid}`);
process.on("SIGHUP", () => console.log("受信: SIGHUP"));
process.on("SIGINT", () => console.log("受信: SIGINT"));
setTimeout(() => {}, 5 * 60 * 1000); // プロセスを継続する

このコードをコマンド ライン ウィンドウで実行し、Ctrl + C を押します。プロセスは終了しません。代わりに、SIGINT シグナルが受信されたことを示すログ情報の行がコンソールに出力されます。新しいコマンド ライン ウィンドウを開き、次のコマンドを実行します。PROCESS_ID は、上記のプログラムによって出力されたプロセス ID です。

kill -s SIGHUP <プロセスID>

新しいコマンドラインを通じて、元のプログラム プロセスに SIGHUP シグナルが送信され、SIGHUP シグナルが受信されたことを示すログ情報の行が元のコマンドライン ウィンドウに出力されます。

NodeJS コードでは、プロセスは他のプロセスにシグナルを送信することもできます。例えば:

node -e "process.kill(<PROCESS_ID>, 'SIGHUP')"

このコードは、SIGHUP シグナルが受信されたことを示すログ行を最初のコマンド ライン ウィンドウに出力します。

最初のコマンド ライン ウィンドウのプロセスを終了したい場合は、次のコマンドを使用します。

kill -9 <プロセスID>

NodeJS では、プロセスの正常な終了を制御するためにシグナルがよく使用されます。たとえば、Kubernetes では、ポッドが終了しようとすると、k8s はポッド内のプロセスに SIGTERM シグナルを送信し、30 秒のタイマーを開始します。アプリケーションには、接続を閉じたり、データを保存するなどの操作を行うのに 30 秒かかります。 30 秒経過してもプロセスがまだ実行中の場合、k8s は別の SIGKILL を送信してプロセスを強制的に閉じます。

まとめ

この記事では、プロセスが終了する原因となるいくつかの要因について説明します。

  • 積極的な撤退
  • キャッチされない例外、処理されないプロミス拒否、処理されないイベントエミッターエラーイベント
  • システム信号

NodeJS プロセスを終了する方法についての記事はこれで終わりです。NodeJS プロセス終了の詳細については、123WORDPRESS.COM の以前の記事を検索するか、以下の関連記事を引き続き参照してください。今後とも 123WORDPRESS.COM をよろしくお願いいたします。

以下もご興味があるかもしれません:
  • Node.js プロセス終了の詳細な理解

<<:  MySQLで負荷分散を実装する方法

>>:  Centos7でのパーティションのフォーマットとマウントの実装

推薦する

Vue でのスロット配置と使用状況分析

このチュートリアルの動作環境: Windows 7 システム、vue 2.9.6 バージョン、DEL...

MySQLで指定した時間前にレコードを自動的に削除する方法

イベントについて: MySQL 5.1 では、イベントの概念が導入され始めました。イベントは「時間ト...

HTML+CSS+JavaScript でシンプルな三目並べゲームを作成する

目次HTMLの実装CSSを追加Javascript部分の実装デモアドレス HTMLの実装まず、hea...

Windows 10 で MySQL をダウンロードするための詳細なチュートリアル

MySQL のバージョンは、Enterprise Edition と Community Editi...

ウェブデザインにおけるグリッドシステム

グリッドシステムの形成1692年、新しく即位したフランス国王ルイ14世は、フランスの印刷技術のレベル...

Nginx をベースに特定の IP への短期アクセス数を制限する

特定の期間内に特定の IP へのアクセス回数を制限する方法は、特に悪意のある DDOS 攻撃に直面し...

JS と Nodejs におけるイベント駆動型開発についての簡単な説明

目次イベント駆動型とパブリッシュ・サブスクライブ型ブラウザの JavaScript ではイベント駆動...

VueのTodoListケースの詳しい説明

<テンプレート> <div id="ルート"> <...

ネイティブ JavaScript でシンプルな Gobang ゲームを実装する

この記事では、JavaScriptで簡単なGobangゲームを実装するための具体的なコードを参考まで...

Vue2で配列の変更を検出できない理由と解決策

目次回避策Vue2.0 で 2 つの配列の変更を監視できないのはなぜですか?ソースコード分析ヴュー3...

JavaScriptカスタムオブジェクトメソッドの概要

目次1. オブジェクトを使用してオブジェクトを作成する2. コンストラクタを使用してオブジェクトを作...

CentOS8.0 で FTP サーバーをインストールして設定する方法

CentOS8.0-1905 のリリース後、FTP サーバーを CentOS の新しいバージョンに移...

シンプルなスネークを実現するためのネイティブjsキャンバス

この記事では、参考までに、簡単なスネークゲームを実装するためのjsキャンバスの具体的なコードを共有し...

MySQLデータベースでの値の追加、変更、削除、クリアの例

3. MySQLデータ管理最初の方法:お勧めできません。複雑そうです -- 学生テーブルの grad...

MySQL での Join の使用に関する詳細な説明

前の章では、1 つのテーブルからデータを読み取る方法を学習しました。これは比較的簡単ですが、実際のア...