Webアプリで処理中に外部実行したコマンドは接続を切るとどうなるか
若いメンバーに説明しないといけなかったので、メモしとく。
テスト用のコード
実行されるWebアプリの処理は下記(環境変わってrailsいじるようになった)。 systemでsleepコマンドを実行する。 systemはlinuxのsystemコマンドを実行する(rubyのドキュメントにsystemコマンドのリンクあったし...)。
test_controller.rb
class TestController < ApplicationController def index system(`sleep 100`) render status: 200, json: @controller.to_json end end
確認手順
- ブラウザでサーバ(http://localhost:3000/test/index)にアクセスする
- ブラウザを閉じる
- ps -ef, pstree -pでプロセスを確認
ちなみに、dockerで環境作ってます。
結果
$ ps -ef
UID PID PPID C STIME TTY TIME CMD user 1 0 0 22:08 ? 00:00:01 puma 3.12.2 (tcp://0.0.0.0:3000) user 79 1 0 22:13 ? 00:00:00 sleep 1000
$ pstree -p
ruby(1)-+-sleep(79) |-{ruby}(51) |-{ruby}(52) |-{ruby}(53) |-{ruby}(54) |-{ruby}(55) |-{ruby}(56) |-{ruby}(57) |-{ruby}(58) |-{ruby}(59) |-{ruby}(60) |-{ruby}(61) |-{ruby}(62) |-{ruby}(63) |-{ruby}(64) `-{ruby}(78)
ということで、接続切ってもプロセスは動いている。
なんで
systemコマンドはforkして子プロセスを生成し、生成された子プロセスがexecを使ってshでコマンドを実行する。
execl(<shell path>, "sh", "-c", command, (char *)0);
つまり、rubyがsystemコマンドで子プロセス(sh)を生成し、さらにshが子プロセス(sleep)を生成して実行する。 shは子プロセスを生成したらすぐに終了するので、sleepの親プロセスは、親の親であるrubyになる、という感じ。