Rails3でdelayed_jobを使って、非同期処理を行う

collectiveidea/delayed_job · GitHub


delayed_jobはHerokuでも使えるみたいなので、Rails3で動かしてみました。
簡単な設定だけで、非同期処理が実装できます。


今回はメール送信する部分を非同期にしてみました。


Gemfile

gem 'delayed_job'

この一行を追加します。

$ bundle install

gemをインストールします。


Rakefile

begin
  require 'delayed/tasks'
rescue LoadError
  STDERR.puts "Run `rake gems:install` to install delayed_job"
end

これでdelayed_jobのrakeタスクを使えるようになります。


config/initializers/delayed_job.rb

Delayed::Worker.destroy_failed_jobs = false
Delayed::Worker.sleep_delay = 60
Delayed::Worker.max_attempts = 3
Delayed::Worker.max_run_time = 5.minutes

delayed_jobの設定をします。


db/migrate/20100909011916_create_delayed_jobs.rb

class CreateDelayedJobs < ActiveRecord::Migration
  def self.up
    create_table :delayed_jobs, :force => true do |table|
      table.integer  :priority, :default => 0      # Allows some jobs to jump to the front of the queue
      table.integer  :attempts, :default => 0      # Provides for retries, but still fail eventually.
      table.text     :handler                      # YAML-encoded string of the object that will do work
      table.text     :last_error                   # reason for last failure (See Note below)
      table.datetime :run_at                       # When to run. Could be Time.zone.now for immediately, or sometime in the future.
      table.datetime :locked_at                    # Set when a client is working on this object
      table.datetime :failed_at                    # Set when all retries have failed (actually, by default, the record is deleted instead)
      table.string   :locked_by                    # Who is working on this object (if locked)
      table.timestamps
    end

    add_index :delayed_jobs, [:priority, :run_at], :name => 'delayed_jobs_priority'
  end
  
  def self.down
    drop_table :delayed_jobs  
  end
end

rails g migration create_delayed_jobs」でマイグレーションファイルを作成します。
※Rails3は「ruby script/generate delayed_job」が使えませんでした。

$ rake db:migrate

マイグレートを実行します。


あとは、アプリ側のメール送信部分を以下のように修正して
「rake jobs:work」を別プロセスで起動しておけば完了です。
とっても簡単!!

# 修正前
@user.deliver_activation_confirmation!
# 修正後
@user.send_later(:deliver_activation_confirmation!)