メールの送信やランキング集計といった、時間がかかる(かもしれない)処理をバックグラウンドで実行したいので、手軽に導入できそうな DelayedJob を試してみた。
DelayedJob をインストール
Gemfile に
gem 'delayed_job_active_record'
を追加して
bundle
を実行。
delayed_job ではなく delayed_job_active_record なので注意。delayed_job だけだと、DelayedJob で ActiveRecord が使えなかった。
bundle exec rails g delayed_job:active_record
を実行するとマイグレーションファイルやスクリプトが生成されるので、あとは
bundle exec rake db:migrate
でテーブルを作成すればインストール完了。
DelayedJob はジョブキューにデータベースを使うから、ジョブキュー用にわざわざミドルウェアを導入しなくてもいい。この手軽さが一番の長所だと思う。
メール送信を非同期にしてみる
まずは定番から。
class ContactsController < ApplicationController ... def create @contact = Contact.new(params[:contact]) if @contact.valid? # 非同期に問い合わせメールを送信 ContactMailer.delay.contact(@contact) end respond_with @contact end end
あれ?deliver メソッドは?って最初戸惑ったけど、DelayedJob 側で実行してくれるから無問題。
常に非同期で実行したいメソッドを定義してみる
ランキング集計とか。
class BookarmkCalculator def calculate_daily(date) Bookmark.where("created_at >= ? AND created_at < ?", date, date.tomorrow) .group("entry_id") .select("entry_id, count(id) as bookmark_count") .order("bookmark_count DESC, comci_id ASC") end # 常に非同期で実行させる handle_asynchronously :calculate_daily end
handle_asynchronously に指定したメソッドは、常に非同期で実行される。毎回 delay を書かなくていい。
あとは
c = BookmarkCalculator.new ranking = c.calculate_daily(Date.today)
こんな感じで呼び出せば、非同期に集計できる。
これを 1日1回、定期的に実行したいんだけど…DelayedJob は遅延実行だけで定期的な実行はできなかったorz
定期的にランキングを集計するには他の RubyGems を使わないといけないのか。