マイ備忘録

あくまで個人の意見、メモです。

Webアプリで処理中に外部実行したコマンドは接続を切るとどうなるか

若いメンバーに説明しないといけなかったので、メモしとく。

テスト用のコード

実行されるWebアプリの処理は下記(環境変わってrailsいじるようになった)。 systemでsleepコマンドを実行する。 systemはlinuxのsystemコマンドを実行する(rubyのドキュメントにsystemコマンドのリンクあったし...)。

pubs.opengroup.org

test_controller.rb

class TestController < ApplicationController
  def index
    system(`sleep 100`)
    render status: 200, json: @controller.to_json 
  end
end

確認手順

  1. ブラウザでサーバ(http://localhost:3000/test/index)にアクセスする
  2. ブラウザを閉じる
  3. 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になる、という感じ。