kentana20 技忘録

技術ネタを中心に、セミナー、勉強会、書籍、会社での出来事を綴っていきます。不定期更新。

Railsアプリのバックグラウンド処理をWheneverを使ってCron化する

Railsアプリの話。というかWheneverの話。

Railsアプリケーションを実装していて、「この処理はオンラインではなくて、バックグラウンドでバッチ処理にして、Cronで定期実行したいな」っていうとき、ありますよね。そんな時は whenever というgemを使えば、カンタンにバッチ処理をCron化できます。

Wheneverを使ってバックグラウンド処理をCron化する

Wheneverのインストール

まずはBundlerを使って、Wheneverをインストールします。

# Gemfile
gem 'whenever', :require => false

Gemfileに書いたら、bundle install します。

$ bundle install

インストールできたら、一応 gem list でwheneverがインストールできているかを確認します。

$ gem list

インストールされているgemにwheneverが追加されていればOKです。

Wheneverで動かすバックグラウンド処理を作る

続いて、Wheneverで動かすバックグラウンド処理(バッチプログラム的なもの)を作っていきます。Railsのお作法的には、バックグラウンド処理は

  • /lib/tasks/

配下に書くのが正しいカタチのようなので、お作法に従ってバックグラウンド処理を書いていきます。

# /lib/tasks/test.rb
class Test
  def self.hoge
    puts "hoge"
  end
end

続いて、 /lib/ 配下をロードするように /config/application.rb に以下を追加します。

# /config/application.rb
module xxx # railsアプリ名
  class Application < Rails::Application
    config.autoload_paths += %W(#{config.root}/lib)
    config.autoload_paths += Dir["#{config.root}/lib/**/"]
  end
end

ここまで出来たら、以下のコマンドを実行してバックグラウンドで動作する処理が正しく動くことを確認します。

$ rails runner Test.hoge # 'hoge'と返ってくればOK

Wheneverを使ってCronジョブを設定する

以下のコマンドを入力して、wheneverを動かすためのひな形(schedule.rb)を作成します。

$ wheneverize . # /config/schedule.rb が作成されます

作成した schedule.rb にCronで動作させたい処理を記述します。記述方法についてはこちらを参照くださいませ。

# /config/schedule.rb
set :environment, :development
set :output, {:error => 'log/error.log', :standard => 'log/cron.log'}

# Testなので、3分毎に動作するように設定します
every 3.minute do
  # cronのコマンドライン上で動くので、二重引用符で囲っておきます
  runner "Test.hoge"
end

schedule.rb の内容をCronへ登録します。

$ bundle exec whenever --update-cron

これで、crontabにジョブが登録されます。登録内容を確認したければ、

$ bundle exec whenever

とか

$ crontab -e

とかで確認可能です。

登録したジョブを削除(Cron設定の解除)をしたい場合は

$ bundle exec whenever --clear-cron

とすれば削除できます。いや〜、カンタンですね。

所感

今回、初めてWheneverを触りましたが

  • バックグラウンドに移したい処理が既にある
  • Cronの設定方法をある程度理解している

という状況であれば、学習コストは殆どナシでCron化できて便利です。また、Railsアプリの一部(レポジトリを1つ)としてCron設定を管理できるので

  • Cron設定をレポジトリ管理できる
  • RubyでCronを記述できる
  • Webアプリとセットで管理できる

など、イロイロな面でメリットがあるな、と感じました。

また、Capistranoとかと連携すればアプリのデプロイ時に

  • /lib/tasks/ 配下
  • /config/schedule.rb

に変更があった場合は bundle exec whenever --update-cron する、みたいなことを deploy.rb に書いておいてCron設定まで自働化しておけば、「一部のノードだけCron設定を更新し忘れた」みたいなこともなくなるハズなので、いい感じでアプリを管理できそうです。

Railsの便利さ(Wheneverの便利さ?)を改めて感じた3連休最終日でした。