プロセスの終了 kill
止めたはずのアプリが、ポートを掴んだまま離さない
デプロイし直そうとすると address already in use と言われる。前のプロセスがまだ生きています。ターミナルは閉じたのに、そのプロセスは別のところで動き続けている、という状況です。
こういうときに使うのが kill です。名前は物騒ですが、実際にやっているのは合図を送ることだけで、その合図を受けてどうするかは相手のプロセスが決めます。だから kill を打っても止まらないことがありますし、止める以外の合図もあります。
まず「片付けてから終わって」と頼む
ターミナル
$ ps -ef | grep "node /app/server.js" | grep -v grep
deploy 2100 1 0 09:05 ? 00:01:23 node /app/server.js
$ kill 2100番号だけを渡すと、終了してほしいという依頼が送られます。これを受け取ったプロセスは、書きかけのファイルを閉じる、処理中のリクエストを返しきる、一時ファイルを消す、といった後片付けをしてから、自分で終了します。データベースやアプリケーションサーバーは、この依頼に対する処理を最初から持っているのが普通です。
止まったかどうかは、少し待ってからもう一度 ps で探せば分かります。見つからなければ成功です。
それでも消えないときだけ、問答無用に切り替える
ターミナル
$ kill -9 2100-9 を付けると、プロセス本人には一切通知されず、カーネルが直接そのプロセスを消します。相手が無限ループに入っているときや、終了処理そのものが固まっているときは、これしかありません。
ただし後片付けは一切行われません。書きかけのファイルは中途半端なまま残り、確保していた一時ファイルやロックファイルも消えずに残ります。データベースを -9 で落とすと、次の起動で復旧処理が走り、最悪の場合はデータが壊れます。最初の手段としては使わず、普通の kill を試して、数秒待っても消えないときだけに限ってください。
名前で送ると、似た名前まで巻き込む
ターミナル
$ pgrep -af "node /app/server.js"
2100 node /app/server.js
$ pkill -f "node /app/server.js"番号を毎回調べるのが面倒なときは、pkill で名前を指定できます。-f を付けるとコマンド行全体に対して照合するので、node とだけ書いて別の Node アプリまで巻き込む事故を避けられます。
pkillを打つ前に、同じ条件でpgrep -afを打ってください。合図が飛ぶ相手の一覧がそのまま出るので、意図しないものが混ざっていればそこで気づけます。pkillは確認を聞いてこないので、気づける場所はここだけです。
課題
- sleep をバックグラウンドで起動する
- kill で確実に終了させる
- wait で後始末する