Ruby on Railsで環境変数を新規に設定したらunicorn:restartでは駄目だった

# 以前の投稿 (環境変数にパスワードを埋め込んでdeployするまで)
Ruby on Railsで githubなどにcommitしたくないパスワードなどを環境変数に設定してcapistranoでdeployする方法
http://qiita.com/kenjiszk/items/2e45660ce3b46596dfa1

自前で、unicorn起動時に環境変数をよんでから実行していた。

# unicorn:restartでは環境変数をよみ直してくれない
## unicornにUSR2を送ってみる
unicorn:restartは内部的にUSR2を送ってホットデプロイしているのでそれを観察する

unicornのシグナルに関しての詳細はこちら。
http://qiita.com/kenjiszk/items/7c6edc7f579ab068591a

### 元のプロセス
pid 237の親に二つ子プロセスがいる状態。

```
$ pstree -anp; ps aux | grep unicorn
bash,1
  |-sshd,35
  |-nginx,44
  |   `-nginx,45
  `-ruby,237                                                    
      |-{ruby},260
      |-{ruby},261
      |-{ruby},265
      |-ruby,269                                                 
      |   `-{ruby},271
      |-ruby,274                                                 
      |   `-{ruby},276
      `-{ruby},275
app     237  0.5  3.9 519760 159992 ?       Sl   22:37   0:09 unicorn master -c config/unicorn.rb -D -E development                                                    
app     269  0.0  3.7 519760 152916 ?       Sl   22:37   0:00 unicorn worker[0] -c config/unicorn.rb -D -E development                                                 
app     274  0.0  3.7 519760 152916 ?       Sl   22:37   0:00 unicorn worker[1] -c config/unicorn.rb -D -E development                                                 
app     311  0.0  0.0   8860   644 ?        S+   23:05   0:00 grep --color=auto unicorn
```

### kill -s USR2 237 してみる
親にUSR2を送ってみる
すると新しい親(pid312)が、シグナルが送られたプロセスの子供として生まれる

```
$ pstree -anp; ps aux | grep unicorn
bash,1
  |-sshd,35
  |-nginx,44
  |   `-nginx,45
  `-ruby,237                                              
      |-{ruby},260
      |-{ruby},261
      |-{ruby},265
      |-ruby,269                                                 
      |   `-{ruby},271
      |-ruby,274                                                 
      |   `-{ruby},276
      |-ruby,312 /path/to/app/shared/bundle/ruby/2.2.0/bin/unicorn -c config/unicorn.rb -D -E development
      |   `-{ruby},315
      `-{ruby},313
app     237  0.5  3.9 585296 159996 ?       Sl   22:37   0:09 unicorn master (old) -c config/unicorn.rb -D -E development                                              
app     269  0.0  3.7 519760 152916 ?       Sl   22:37   0:00 unicorn worker[0] -c config/unicorn.rb -D -E development                                                 
app     274  0.0  3.7 519760 152916 ?       Sl   22:37   0:00 unicorn worker[1] -c config/unicorn.rb -D -E development                                                 
app     312 54.0  0.5  89600 21940 ?        Rl   23:06   0:01 ruby /path/to/app/shared/bundle/ruby/2.2.0/bin/unicorn -D -E development
app     318  0.0  0.0   8860   644 ?        S+   23:06   0:00 grep --color=auto unicorn
```

### 新プロセスが子供を作る
新しい親がスレッド作ったりして色々と頑張り始める

```
$ pstree -anp; ps aux | grep unicorn
bash,1
  |-sshd,35
  |-nginx,44
  |   `-nginx,45
  `-ruby,237                                              
      |-{ruby},260
      |-{ruby},261
      |-{ruby},265
      |-ruby,269                                                 
      |   `-{ruby},271
      |-ruby,274                                                 
      |   `-{ruby},276
      |-ruby,312 /path/to/app/shared/bundle/ruby/2.2.0/bin/unicorn -c config/unicorn.rb -D -E development
      |   |-{ruby},315
      |   |-{ruby},329
      |   |-{ruby},330
      |   `-{ruby},334
      `-{ruby},313
app     237  0.5  3.9 585296 159996 ?       Sl   22:37   0:09 unicorn master (old) -c config/unicorn.rb -D -E development                                              
app     269  0.0  3.7 519760 152916 ?       Sl   22:37   0:00 unicorn worker[0] -c config/unicorn.rb -D -E development                                                 
app     274  0.0  3.7 519760 152916 ?       Sl   22:37   0:00 unicorn worker[1] -c config/unicorn.rb -D -E development                                                 
app     312 96.6  3.9 521744 161428 ?       Rl   23:06   0:11 ruby /path/to/app/shared/bundle/ruby/2.2.0/bin/unicorn -c config/unicorn.rb -D -E development
app     337  0.0  0.0   8860   648 ?        S+   23:06   0:00 grep --color=auto unicorn
```

### 入れ替わり
新親が子プロセスを作る終わって、元の親がいなくなり、新親の親はinitになる。

```
$ pstree -anp; ps aux | grep unicorn
bash,1
  |-sshd,35
  |-nginx,44
  |   `-nginx,45
  `-ruby,312                                                    
      |-{ruby},329
      |-{ruby},330
      |-{ruby},334
      |-ruby,338                                                 
      |   `-{ruby},340
      |-ruby,343                                                 
      |   `-{ruby},345
      `-{ruby},344
app     312 69.2  3.9 521748 161852 ?       Sl   23:06   0:11 unicorn master -c config/unicorn.rb -D -E development                                                    
app     338  0.5  3.8 521748 154628 ?       Sl   23:06   0:00 unicorn worker[0] -c config/unicorn.rb -D -E development                                                 
app     343  0.2  3.8 521748 154608 ?       Sl   23:06   0:00 unicorn worker[1] -c config/unicorn.rb -D -E development                                                 
app     352  0.0  0.0   8860   648 ?        S+   23:06   0:00 grep --color=auto unicorn
```

## USR2だと環境変数はよみ直さない
ということで、自分のコピーを作るだけなので環境変数は新しくしても読み込まないし、環境変数を消してもプロセスには残っている状態になっている。

# 仕方ないのでstop startする
## 対応
config/deploy.rbをこんな感じにしました。
今の環境だと、/path/to/secret/yml/env.ymlに環境変数に読み込むものを書いているので、そこのタイムスタンプが起動しているunicornのpidのタイムスタンプよりも新しかったら、unicornをstopして、unicorn_stop_sleep_time秒後にstartするように変更。
ついでに、rubyがバージョンアップした場合にもstop startするようにした。

```
namespace :deploy do

  task :restart do
    on roles(:app), in: :sequence, wait: 5 do
      # unix command execute status;
      # 0 : true
      # 1 : false
      old_env = capture(
        "/usr/bin/test /path/to/secret/yml/env.yml -ot #{fetch(:deploy_to)}/shared/tmp/pids/unicorn.pid; echo $?"
      )
      old_ruby = capture(
        "/usr/bin/test /home/app/.rbenv/versions/#{fetch(:rbenv_ruby)} -ot #{fetch(:deploy_to)}/shared/tmp/pids/unicorn.pid; echo $?"
      )
      if old_env == '0' && old_ruby == '0'
        info 'env.yml and ruby version is old. restat unicorn.'
        invoke 'unicorn:restart'
      else
        info 'env.yml or ruby version is new. stop and start(reload env.yml) unicorn.'
        invoke 'unicorn:stop'
        execute :sleep, fetch(:unicorn_stop_sleep_time)
        invoke 'unicorn:start'
      end
    end
  end
  
  after :publishing, :restart
end
```

# まとめ
gitにcommitしたくないものをどうやって環境変数に持たせるか、から始まりunicornの再起動まで気を使う事になってきた。
実はもっといい方法がどこかにあるんじゃないかと思いつつもひとまずこれで運用する。