処理に時間のかかるプログラムをSSHから実行していたのですが、別の作業をするため、SSHを切断して、処理の完了時間を待っていました。
一向に処理が完了している気配がなく、調べてみると、途中で処理が止まってしまっていたことがありました。
この理由について調べてみました。
目次
事象が発生するケース
- 処理に時間のかかる処理を実行するとき
- デーモンを使わずに、HTTPサービスを実行するとき
※SSHを使って、httpdを実行した時はこの事象は発生しません。
SSH接続切断時にプログラムが停止する原因
プログラムが停止する理由は、SIGHUPシグナルが原因でした。
SSH接続をしたうえで実行するプログラムは、SSHの子プロセスとして動作します。
SSH接続終了時に、SSHの子プロセスにはSIGHUPシグナルが送出されます。
子プロセスがこのSIGHUPを受け取ると、SSH接続が終了したと判断し、プロセスが終了します。
動作確認
動作の確認をしてみました。
プログラム実行時とSIGHUPシグナル受信時にログを残すプログラムを実行してみます。
この通り、TeratermによるSSH接続終了時にSIGHUPを受信していることが分かります。
フォアグラウンドプロセス、バックグラウンドプロセスに関わらずウィンドウからSSHを切断すると、SIGHUPが送られるようです。
【 exit 】コマンドを実行して処理を終了した場合
私が動作を確認していたところ、SSH経由で実行するプログラムをバックグラウンドプロセスにして、
[ exit ] コマンドを実行し、SSH接続を終了した場合にはSIGHUPが受信されませんでした。
[ exit ] を実行しましたが、SIGHUPをプログラムが受信しておらず、PPID(親プロセスID)が1になっています。
[ exit ] を実行した場合には、Tera Termがグレースフルシャットダウンすることで、継続中のプロセスは継続されるのではないかと思われます。
[ exit ] コマンドを実行する習慣がなかった頃によく遭遇していた気がします。
対処法
SIGHUPを無視させるコマンドとして、nohupコマンドがあります。
nohupコマンドは、SIGHUPシグナルを無視させるコマンドです。SSH接続終了後もプロセスを動かすことができます。
nohupコマンドを使って、60秒間処理が持続するプログラムをフォアグラウンドプロセスで実行したところ以下のようになります。
ウィンドウからSSHを切断しても以下のように、親プロセスがつけ変わっています。
付録:処理に長時間かかるプログラムを既に実行してしまったあなたへ
SSH経由で、処理に長時間かかるプログラムを既に実行してしまっている場合の対応方法を紹介します。
nohupコマンドを使って、プログラムを実行すれば、SIGHUPを無視できますが、既に実行してしまっている方もいらっしゃると思います。
disownコマンドを使うことで、SSHセッションからバッググラウンドプロセス(ジョブ)を切り離すことができます。
下記の手順を踏むことで対応することが可能です。
まとめ
本件調査をしてみましたが、OSの仕組みであるシグナルまで調べることになるとは思いもよりませんでした。
この件を通じて、OSの仕組みを調べるきっかけになったので、小さな気づきを無視しないことは大事なのだと思いました。
記載されている会社名、システム名、製品名は一般に各社の登録商標または商標です。
当社製品以外のサードパーティ製品の設定内容につきましては、弊社サポート対象外となります。