Quantcast
Channel: Node.jsタグが付けられた新着記事 - Qiita
Viewing all articles
Browse latest Browse all 9027

Express (Node.js) の Graceful shutdown

$
0
0

基本的な実装の仕方と、実装した場合 / しなかった場合、で実際にどういう動作をするか〜、について書きます。

Linux, Node.js 12.13.0, での話だけをします。

Graceful shutdown ?

Express (Node.js) に限りませんが、Web サーバーを停止する際、クライアントから接続中のリクエスト (リクエスト受付してまだレスポンスしていない接続) はどうなるでしょうか?

Graceful shutdown とは一般的に以下の停止を指します。

  • 停止指示後に、新しい接続を受付しない
  • 残った処理中の接続が完了するのを待ってから、プロセスを安全に停止する

SIGNALs

そもそも Web サーバープロセスはどうやって停止するかというと、 SIGNALを用いて停止します。

具体的には下表の通り、コマンド等によって SIGNALを送信できます。

SIGNALkill commandLinux TerminalKubernetes実装依存説明
SIGHUPkill -SIGHUP {pid}----Yesプロセスが端末から切断された際のシグナル
SIGINTkill -SIGINT {pid}CTRL + C--Yes割り込み
SIGKILLkill -SIGKILL {pid}--SIGTERM 送信から30秒後に送信NOプロセスの実装に依存しないOSからの強制終了
SIGTERMkill {pid}--最初に送信Yesプロセスの終了

最近では、プロセスを Dockerコンテナ化して、 Kubernetes等のプラットフォーム上で動かす事が多いと思います。

例えば Kubernetesでは、プロセス (Dockerコンテナ) を終了する際は、まず SIGTERMが送信され、30秒待ってもプロセスが終了しない場合、最終的に SIGKILLが送信されます。

Kubernetes - Pods - Termination of Pods

実装例

URL /sleepと、 SIGNAL SIGTERMでの Graceful shutdown を Expressで実装しました。

index.js
constexpress=require('express');constSLEEP_MSEC=30*1000;constapp=express();app.get('/sleep',(req,res)=>{setTimeout(()=>res.send('OK'),SLEEP_MSEC);});constserver=app.listen(3000,()=>console.log('Example app listening on port 3000!'));process.on('SIGTERM',()=>{server.close(()=>{console.log('Process terminated.')})});

実行します。

$ node index.js

Example app listening on port 3000!

ブラウザで以下の URL にアクセスすると、30秒待たされた後 OKと表示されます。

[未実装で] 実際に停止してみる

まずは 未実装の状態でどう動作するか検証します。

Express サーバーを起動した後、ブラウザで http://localhost:3000/sleepにアクセスします。
まだリクエストの処理中に SIGNALを送信します。

(1) SIGHUP

シグナルを送信でプロセスが即座に停止。

kill-SIGHUP{pid}
Hangup: 1

(2) SIGINT

シグナルを送信でプロセスが即座に停止。

kill-SIGINT{pid}
(terminal 上の出力はなし)

(3) SIGKILL

シグナルを送信でプロセスが即座に停止。

kill-SIGKILL{pid}
Killed: 9

(4) SIGTERM

シグナルを送信でプロセスが即座に停止。

kill{pid}
Terminated: 15

[SIGTERM 実装で] 実際に停止してみる

実装していない SIGTERM以外のシグナルは省略。

(5) SIGTERM

ブラウザで http://localhost:3000/sleepにアクセスする。

応答がすぐには帰ってこず、ローディング状態になります。

シグナルを送信します。

kill{pid}

プロセスは実行されたまま、無反応。

(terminal 上の出力はなし)

ブラウザから新しいタブを開いて http://localhost:3000/sleepに追加でアクセスする。

TCP 接続が拒否され、ブラウザ上に「正常に接続できませんでした」と表示される。

1度目のブラウザからのリクエストが 30 秒後に正常に応答が返り、プロセスが終了する。

Process terminated.

Viewing all articles
Browse latest Browse all 9027

Trending Articles