[何となく知ってたけど再確認] capistrano3-unicornがunicornに送るシグナルまとめ


# capistrano3-unicorn
capistrano + rails + unicornという構成の時に、unicornを色々と操作するやつ。
unicornを再起動したり色々としてくれる。
https://github.com/tablexi/capistrano3-unicorn/blob/a4adb59031b001a9cd8f9dce5f4beb3200c80f8d/lib/capistrano3/tasks/unicorn.rake

# killとは

システムコールのkillは、任意のプロセス・グループもしくはプロセスにシグナルを送るのに使われる。
<font color=red>始めてkillというコマンドを知った時にはみんな誤解したはず。killはプロセスに命令を送るコマンド(殺すやつじゃない)</red>

# シグナルを全部追うと大変なのでcapistrano3-unicornが発行している物だけ抜粋

## kill -0

0はプロセスがいるかどうか確認するだけ。
プロセスがいない場合には、エラーが返っている。

```
$ ps aux | grep [u]nicorn
ubuntu    1886  0.0  2.7 390020 111700 ?       Sl   12:21   0:05 unicorn master -c /xxx/unicorn/development.rb -E development -D
ubuntu    1899  0.0  2.8 402224 117272 ?       Sl   12:22   0:00 unicorn worker[0] -c /xxx/unicorn/development.rb -E development -D

$ kill -0 1886
$ echo $?
0

$ kill -0 1888
-su: kill: (1888) - No such process
$ echo $?
1
```

[code抜粋] unicornのstart時にそもそもunicornが動いているかどうかを確認する為に使われている。

```
desc "Start Unicorn"
  task :start do
    on roles(fetch(:unicorn_roles)) do
      within current_path do
        if test("[ -e #{fetch(:unicorn_pid)} ] && kill -0 #{pid}")
          info "unicorn is running..."
        else
          with rails_env: fetch(:rails_env) do
            execute :bundle, "exec unicorn", "-c", fetch(:unicorn_config_path), "-E", fetch(:unicorn_rack_env), "-D", fetch(:unicorn_options)
          end
        end
      end
    end
  end
```


## kill -s QUIT

キーボードによる中止。QUITを送れはプロセスは止まる。

```
$ ps aux | grep [u]nicorn
ubuntu    1886  0.0  2.7 390020 111700 ?       Sl   12:21   0:05 unicorn master -c /xxx/unicorn/development.rb -E development -D
ubuntu    1899  0.0  2.8 402224 117272 ?       Sl   12:22   0:00 unicorn worker[0] -c /xxx/unicorn/development.rb -E development -D

$ kill -s QUIT 1886
$ ps aux | grep [u]nicorn | wc -l
0
```

[code抜粋] unicornをstopする時に使われている。

```
desc "Stop Unicorn (QUIT)"
  task :stop do
    on roles(fetch(:unicorn_roles)) do
      within current_path do
        if test("[ -e #{fetch(:unicorn_pid)} ]")
          if test("kill -0 #{pid}")
            info "stopping unicorn..."
            execute :kill, "-s QUIT", pid
          else
            info "cleaning up dead unicorn pid..."
            execute :rm, fetch(:unicorn_pid)
          end
        else
          info "unicorn is not running..."
        end
      end
    end
  end
```

## kill -s HUP

制御端末(controlling terminal)のハングアップ検出、
または制御しているプロセスの死
killでシグナルを受け取った場合の挙動は、書かれているプログラムにより異なるが、HUPを受け取るとconfigを読み直してリロードする設計が多く見られる。
unicornもそのようになっている。

親プロセスにHUPを送るとconfigを読み直して子プロセスが新しく起動している(pidが変わっている)

```
$ ps aux | grep [u]nicorn
ubuntu    2056 42.1  2.7 323096 111164 ?       Sl   14:25   0:04 unicorn master -c /xxx/unicorn/development.rb -D -E development
ubuntu    2061  0.0  2.6 323096 105848 ?       Sl   14:25   0:00 unicorn worker[0] -c /xxx/unicorn/development.rb -D -E development

$ kill -s HUP 2056

$ ps aux | grep [u]nicorn
ubuntu    2056  6.0  2.7 388632 111244 ?       Sl   14:25   0:04 unicorn master -c /xxx/unicorn/development.rb -D -E development
ubuntu    2066  0.0  2.6 388632 105856 ?       Sl   14:26   0:00 unicorn worker[0] -c /xxx/unicorn/development.rb -D -E development
```

[code抜粋] unicornのreloadで使われている

```
desc "Reload Unicorn (HUP); use this when preload_app: false"
  task :reload do
    invoke "unicorn:start"
    on roles(fetch(:unicorn_roles)) do
      within current_path do
        info "reloading..."
        execute :kill, "-s HUP", pid
      end
    end
  end
```

## kill -s USR2

ユーザー定義シグナル。
これも実装側で挙動を決める。unicornのは合いUSR2を受け取ると親プロセスごと新しく生まれ変わる。

実際に打ってみると確かに、親プロセスのpidが変わっている。

```
$ ps aux | grep [u]nicorn
ubuntu    2056  2.1  2.7 388632 111244 ?       Sl   14:25   0:04 unicorn master -c /xxx/unicorn/development.rb -D -E development
ubuntu    2066  0.0  2.6 388632 105856 ?       Sl   14:26   0:00 unicorn worker[0] -c /xxx/unicorn/development.rb -D -E development

$ kill -s USR2 2056

$ ps aux | grep [u]nicorn
ubuntu    2073 32.3  2.7 389848 111600 ?       Sl   14:29   0:05 unicorn master -c /xxx/unicorn/development.rb -D -E development
ubuntu    2084  0.0  2.5 390000 105020 ?       Sl   14:29   0:00 unicorn worker[0] -c /xxx/unicorn/development.rb -D -E development
```

[code抜粋] unicornのrestartで使われている

```
desc "Restart Unicorn (USR2); use this when preload_app: true"
  task :restart do
    invoke "unicorn:start"
    on roles(fetch(:unicorn_roles)) do
      within current_path do
        info "unicorn restarting..."
        execute :kill, "-s USR2", pid
      end
    end
  end
```

## kill -s TTIN / TTOU

バックグランドプロセスの端末入力 / 出力
unicornに送ってみるとなかなか面白く、子プロセスが増えたり減ったりする。
<font color=red>これは相当便利ではないか！</font>
でも、TTINで生まれた子プロセスだけ設定が新しいとか、起きそう。

```
$ kill -s TTIN 2073
$ ps aux | grep [u]nicorn
ubuntu    2073  0.5  2.7 389848 111632 ?       Sl   14:32   0:05 unicorn master -c /xxx/unicorn/development.rb -D -E development
ubuntu    2084  0.0  2.5 390000 105020 ?       Sl   14:32   0:00 unicorn worker[0] -c /xxx/unicorn/development.rb -D -E development
ubuntu    2103  0.0  2.5 389980 104968 ?       Sl   14:48   0:00 unicorn worker[1] -c /xxx/unicorn/development.rb -D -E development

$ kill -s TTOU 2073
$ ps aux | grep [u]nicorn
ubuntu    2073  0.5  2.7 389848 111640 ?       Sl   14:32   0:05 unicorn master -c config/unicorn/development.rb -D -E development                                                         
ubuntu    2084  0.0  2.5 390000 105020 ?       Sl   14:32   0:00 unicorn worker[0] -c config/unicorn/development.rb -D -E development
```

[code抜粋] 当然unicornでプロセス増やしたり減らしたりする時に使う。

```
desc "Add a worker (TTIN)"
  task :add_worker do
    on roles(fetch(:unicorn_roles)) do
      within current_path do
        info "adding worker"
        execute :kill, "-s TTIN", pid
      end
    end
  end

  desc "Remove a worker (TTOU)"
  task :remove_worker do
    on roles(fetch(:unicorn_roles)) do
      within current_path do
        info "removing worker"
        execute :kill, "-s TTOU", pid
      end
    end
  end
end
```

# まとめ
unicornが受け取るシグナルとその挙動を知っていれば、緊急時にちょっとプロセス増やすとか減らすとか、設定を読み直すとかがさくっと出来るので知っていて損はなさそうですね。