Railsアプリのデプロイ自体はcapistranoで行う事が多いが
バッチ処理のcron設定もwheneverを使ってruby側で行う事で一元管理できる。
さらにcapistranoと連携する事でデプロイ時のcrantab設定まで自動化してみる。
設定漏れも防げるし、管理もすっきりするのでいいことずくめ。

wheneverインストール

Gemfileに以下を追加

gem 'whenever', :require => false

railsプロジェクトにインストール

bundle install --path vendor/bundle

以下を実行してschedule.rbを作成

bundle exec wheneverize .

作成したschedule.rbを編集する

  • outputを定義するとログの出力先を指定できる
  • environmentを定義すると環境変数を利用できる
  • crontabの指定は以下のような形でrails風な感じでもcrontab風でもOK
  • job_typeを定義してPATHの定義等カスタマイズする事も可能

    set :output, 'log/crontab.log'
    set :environment, @environment
    
    job_type :runner, "export PATH=\"$HOME/.rbenv/bin:$PATH\"; eval \"$(rbenv init -)\"; cd :path && RAILS_ENV=:environment bundle exec rails runner :task :output"
    
    every 1.day, :at => '1:30 am' do
      command "sh batches/main.sh"
    end
    
    every 1.day, :at => '22:00 pm' do
      runner "Tasks::Testbatch.execute"
    end
    
    every :month, :at => '1:00 am' do
      rake "batch:samplerake"
    end
    

作成して以下を実行するとcrontabに記述されるスケジュールが表示される(この時点では実際には登録されない)

bundle exec whenever --set environment=development

しかしエラーが発生した。

uninitialized constant Whenever::JobList::Tasks (NameError)

Tasksが見つけられないとの事なので以下をschedule.rbに追加

require File.expand_path(File.dirname(__FILE__) + "/environment.rb")

再度[bundle exec whenever]するとcrontab用のテキストが表示された

実際にcrontabに反映するには以下のコマンドを実行する

bundle exec whenever --update-crontab --set environment=development

jobを削除するコマンド(crontabの他jobには影響はない)

bundle exec whenever --clear-crontab --set environment=development

capistranoと連携

とりあえずwheneverを使ってcrontabの設定を出来るようになったので
capistranoに組み込んでデプロイ時に自動反映出来るようにする。

capistranoをインストール

gem install capistrano -v '~>2.15'

※rbenv環境下の場合は以下のような感じでPATHにrbenvを加える

PATH="$HOME/.rbenv/bin:$PATH" sudo gem install capistrano -v '~>2.15'

設定ファイル生成コマンド(アプリケーションルートディレクトリで実行)

capify .

deploy.rbを編集する

細かい設定は使い方はこちらで
https://github.com/capistrano/capistrano

wheneverの設定を追加するためにdeploy.rbを編集

require 'whenever/capistrano'
set :whenever_command, "bundle exec whenever"
set :whenever_environment, defer {'staging'}
set :whenever_roles,defer{"IPADDR:PORT"}
after 'deploy:update', 'whenever:update_crontab'

設定が出来たら試してみる

cap staging deploy

エラーが発生。

Net::SSH::AuthenticationFailed: Authentication failed

以下を参考にnet-sshをバージョン下げて再インストールした
http://stackoverflow.com/questions/21811026/capistrano-cannot-deploy-code-because-netsshauthenticationfailed-authentic

gem uninstall net-ssh -v 2.8.0
gem install net-ssh -v 2.7.0

今度は動いたんだけどwhenever:update_crontabが空振りしてしまう。。。
こちらを参考に上のwhenever_xxxのパラメータ設定を変更
http://stackoverflow.com/questions/21395839/whenever-gem-failing-on-deploy

role :web, target_ip
set :whenever_roles,        ->{ :web }
set :whenever_options,      ->{ {:roles => fetch(:whenever_roles)} }
set :whenever_command,      ->{"bundle exec whenever"}
set :whenever_identifier,   ->{ fetch :application }
set :whenever_environment,  ->{ fetch :rails_env, "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}" }

これで無事動いた。
設定自体はたいした事無いんだけど、色々ハマった。。。