[rails]whenever設定時にSettingsを呼びだそうとしたらハマった(capistrano)


cron設定を管理するのに便利なgemといえばwheneverですね。

今回、whenever使用時にconfig/schedule.rb内で定数管理gem(rails_config)を呼びだそうとしたところエラーが発生しかなりハマりました。

環境に応じてschedule.rbの内容を切り替えたい、という場合が今後もありそうなので対応策をメモしておきます。

rails_configを使う前の設定

最初はSettingsを使っておらず、以下のようなsitemap_generatorの更新処理を書いていてこれは問題ありませんでした。

# config/schedule.rb

rails_env = ENV['RAILS_ENV'] || :production
set :environment, rails_env

every 1.day, :at => '5:00 am' do
  rake "-s sitemap:refresh"
end

set :environmentを環境ごとに指定しておくことで、wheneverが以下のようにRAILS_ENVを自動補完してくれます。

RAILS_ENV=production bundle exec rake -s sitemap:refresh --silent

rails_configを呼びだそうとしてハマった

上記の設定に加えて定期的にバッチのURLにアクセスする設定を追加しました。

バッチURLは自分自身からのアクセス以外は無視するIP制限をかけてあるものとします。

# config/schedule.rb

rails_env = ENV['RAILS_ENV'] || :production
set :environment, rails_env

every 1.day, :at => '5:00 am' do
  rake "-s sitemap:refresh"
end

every 1.day, :at => '0:00 am' do
  command "wget --spider http://#{Settings.host}/batch/test"
end

そのまま bundle exec whenever で設定を確認しようとしたところ、 uninitialized constant エラーが発生。

Rails設定を呼び出すには、schedule.rb内に

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

を記述しておく必要がありました。

というわけで

# config/schedule.rb

ENV['RAILS_ENV'] ||= 'production'

require File.expand_path(File.dirname(__FILE__) + "/environment")  # 追加

set :environment, ENV['RAILS_ENV']

every 1.day, :at => '5:00 am' do
  rake "-s sitemap:refresh"
end

every 1.day, :at => '0:00 am' do
  command "wget --spider http://#{Settings.host}/batch/test"
end

これで手動実行すれば問題なく実行できました。

が、capistrano経由で反映する際にうまくいかず更にハマりました。

capistrano(v3)設定

最初は以下のように設定していたのですが、これだとRAILS_ENVが指定されていないため、デフォルトのdevelopmentでwheneverを実行しようとするためエラーになってしまいました。

set :whenever_roles, 'batch'
set :whenever_identifier, ->{ "#{fetch(:application)}_#{fetch(:stage)}" }

そこで、色々試行錯誤しつつ、最終的にはwheneverのソースコードを見ながら

set :whenever_roles, 'batch'
set :whenever_identifier, ->{ "#{fetch(:application)}_#{fetch(:stage)}" }
set :whenever_command, -> { ["RAILS_ENV=#{fetch(:stage)}", :bundle, :exec, :whenever] } # これを追加

を指定したところ、うまく実行できました。

これでdeploy実行時にbatchロールのサーバにwhenever設定が適用されます。

whenever設定のみ更新したい場合は以下のタスクでできます。

# cron設定更新
cap production whenever:update_crontab

# cron設定解除
cap production whenever:clear_crontab

これはハマりました。

参考