Railsでwheneverを使ってcronを設定する

## 概要
- Railsでcronを管理するためのgem wheneverの使い方
- capistranoでwheneverをセットする方法


## gemインストール
Gemfileに追記

```rb:Gemfile
# cron
gem 'whenever', require: false
```

```
$ bundle install --path vendor/bundle
```

## 初期化
下記コマンドで設定ファイルを作成される

```
$ bundle exec wheneverize .

[add] writing `./config/schedule.rb'
[done] wheneverized!
```

## wheneverの設定

```
$ vi config/schedule.rb
```

```rb:config/schedule.rb
# Rails.rootを使用するために必要
require File.expand_path(File.dirname(__FILE__) + "/environment")
# cronを実行する環境変数
rails_env = ENV['RAILS_ENV'] || :development
# cronを実行する環境変数をセット
set :environment, rails_env
# cronのログの吐き出し場所
set :output, "#{Rails.root}/log/cron.log"

# stagingのみで実行
if rails_env.to_sym != :development
  # clear cache
  every 10.minutes do
    begin
      rake 'sample_task:all', :environment_variable => "RAILS_ENV", :environment => "development"
    rescue => e
      Rails.logger.error("aborted rake task")
      raise e
    end
  end
end
```

第１引数は `:task` としてセットされる。
その他の引数は省略可能だが、その場合は下記のようにデフォルト値がセットされる。

| 変数 | デフォルト値 |
| --- | --- |
| :path | wheneverの実行ディレクトリのパス |
| :environment_variable | RAILS_ENV |
| :environment | production |

#### job_type
自分でjob_typeを作成することもできる。
`your_job_name` の部分は自由に命名できる。



```rb:config/schedule.rb
job_type :your_job_name, 'cd :path && export PATH=/usr/local/bin:$PATH && 
  :environment_variable=:environment bundle exec rake :task --silent :output'

every 2.hours do
  your_job_name "sample_task"
end
```

実際に実行されるコマンド

```
$ cd /project && export PATH=/usr/local/bin:$PATH && \
    RAILS_ENV=production bundle exec rake :task --silent 
```

## cronに反映する際のコマンド
### 設定内容にエラーがないか確認

```
$ bundle exec whenever 
```

### 設定されているcronを見る

```
$ crontab -l
```

### cronにデータを反映

```
$ bundle exec whenever --update-crontab 
```

### cronからデータを削除

```
$ bundle exec whenever --clear-crontab
```

## その他
### 下記コメントアウト外の記述には、削除も更新も、wheneverコマンドでは影響しない

```
# Begin Whenever generated tasks for: /vagrant/project/config/schedule.rb

# End Whenever generated tasks for: /vagrant/project/config/schedule.rb
```

`Begin Whenever generated tasks for:` が、cronとプロジェクトを関連づけているので、update、clearともに、該当のプロジェクトのものしか影響しない。


### `/bin/bash -l` で実行されるので、 `.bash_profile` は読み込まれる。

crontab

```sh
# Begin Whenever generated tasks for: /vagrant/project/releases/20170301131348/config/schedule.rb
0,10,20,30,40,50 * * * * /bin/bash -l -c 'cd /vagrant/project/releases/20170301131348 && RAILS_ENV=staging bundle exec rake sample_task:all --silent >> /vagrant/project/releases/20170301131348/log/cron.log 2>&1'

# End Whenever generated tasks for: /vagrant/project/releases/20170301131348/config/schedule.rb
```



## capistranoでwheneverをセットする方法
Gemfile

capistranoサーバーにもwheneverのインストールが必要

```rb
gem 'whenever', :require => false
```

Capfile

```rb
require 'whenever/capistrano'
```

config/deploy.rb

```rb
set :whenever_roles,        ->{ :app }
```

その他のオプションは、下記のGithubのコードを参照。

[Github: javan/whenever](https://github.com/javan/whenever/blob/master/lib/whenever/capistrano/v3/tasks/whenever.rake)

```rb
namespace :load do
  task :defaults do
    set :whenever_roles,        ->{ :db }
    set :whenever_command,      ->{ [:bundle, :exec, :whenever] }
    set :whenever_command_environment_variables, ->{ { rails_env: fetch(:whenever_environment) } }
    set :whenever_identifier,   ->{ fetch :application }
    set :whenever_environment,  ->{ fetch :rails_env, fetch(:stage, "production") }
    set :whenever_variables,    ->{ "environment=#{fetch :whenever_environment}" }
    set :whenever_update_flags, ->{ "--update-crontab #{fetch :whenever_identifier} --set #{fetch :whenever_variables}" }
    set :whenever_clear_flags,  ->{ "--clear-crontab #{fetch :whenever_identifier}" }
  end
end
```

## 参考
- [Github: javan/whenever](https://github.com/javan/whenever)
- [Railsで定期的にバッチ回す「Whenever」](http://qiita.com/yumiyon/items/388fbb84450f49a6ab0d)
- [Rails の定期実行ジョブはwhenever で](http://kawairi.jp/weblog/vita/2016011520061)
- [gemのwheneverを導入してみた](http://shiro-16.hatenablog.com/entry/2015/02/17/000715)
- [Rubyで自然言語っぽくcrontab管理できるwheneverを使うAdd Star](http://d.hatena.ne.jp/kk_Ataka/20160605/1465121213)
- [PadrinoでWheneverをつかってみる](http://qiita.com/c8112002/items/702a70c4c410441f9064)