bashスクリプトで子プロセスにSIGTERMを転送する
HerokuというPlatform as a Service (PaaS)ではコンテナの停止時にコンテナ内のすべてのプロセスにSIGTERMを送りますが、ナウでヤングなDockerやk8sなどでは親プロセスのみにSIGTERM送るのが一般的なのだそうです。このような状況でも子プロセスにSIGTERMを転送してくれるbashスクリプトを書きます。
#!/bin/bash
bundle exec puma -C config/puma.rb&
bundle exec bin/jobs&
cpids=`pgrep -P $$`;
trap 'for pid in $cpids; do kill -TERM $pid; done' TERM;
wait -n;
kill -TERM $$;
wait
上記のbashスクリプトは、PumaとSolid Queue(bin/jobsコマンド)を子プロセスとして起動して、
- 自スクリプトを実行しているbashプロセスがSIGTERMを受けた、
- 自スクリプトを実行しているbashプロセスと子プロセスがSIGTERMを受けた、あるいは、
- いずれかの子プロセスが何らかの理由で停止した
時に、
- すべての子プロセスにSIGTERMを送って、
- すべての子プロセスが停止したら
- 自スクリプトを実行しているbashプロセスを停止する
ようになっているはずです。
自スクリプトを実行しているbashプロセスのIDを得る
bashスクリプト内の$$パラメータは、それを実行しているbashプロセスのIDに展開されます。
子プロセスのIDを列挙する
シグナルを転送する先のプロセスIDを得るために、pgrepコマンドを利用します。-Pオプションを渡すと指定したプロセスの子プロセスを列挙してくれます。man pgrepより:
-P, --parent ppid,...
Only match processes whose parent process ID is listed.
上記のスクリプトでは、得られたプロセスIDの一覧をシェル変数に格納します。
シグナルを受けた時の動作を指定する
trap組み込みコマンドでスクリプトを実行しているbashプロセスがシグナルを受け取った時の動作を指定できます。文字列として渡した実行内容をシグナルを受け取った時に展開するようです。
上記のスクリプトでは、得られたプロセスIDの一覧を展開します。
子プロセスの終了を待つ
wait組み込みコマンドで子プロセスの終了を待つことができます。-nオプションを付けるといずれかの子プロセスが終了するまでブロックします。オプションを付けないと全ての子プロセスが終了するまでブロックします。
残っている子プロセスにシグナルを送る
上記のスクリプトでは、SIGTERM以外のきっかけでいずれかの子プロセスが停止した場合に、自プロセスにSIGTERMを送ることでtrapに設定したコマンドが実行し残っている子プロセスにもSIGTERMを送ります。