Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
Help us understand the problem. What is going on with this article?

[何となく知ってたけど再確認] 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は、任意のプロセス・グループもしくはプロセスにシグナルを送るのに使われる。
始めてkillというコマンドを知った時にはみんな誤解したはず。killはプロセスに命令を送るコマンド(殺すやつじゃない)

シグナルを全部追うと大変なので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に送ってみるとなかなか面白く、子プロセスが増えたり減ったりする。
これは相当便利ではないか!
でも、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が受け取るシグナルとその挙動を知っていれば、緊急時にちょっとプロセス増やすとか減らすとか、設定を読み直すとかがさくっと出来るので知っていて損はなさそうですね。

kenjiszk
インフラエンジニア 1年ほどiOSに浮気していましたが最近またインフラやってます 最近はRubyとGoもいじってます
http://kenjiszk.hatenablog.com/
finc
健康寿命を伸ばすアプリFiNCの開発・運営を行うモバイルヘルステクノロジーベンチャー
https://finc.com
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away