Active Jobとは?
Ruby on Rails(以下Rails) 4.2からバックグラウンドでジョブを実行するActive Jobが利用できるようになりました。
Active Jobを利用することによって、メールの送信や、バッチ処理などをバックグラウンドで実行することが可能になります。
Railsで利用できるバックグラウンドでのジョブ実行の仕組みとしては、Delayed Job, Resque, Sidekiqなどがありますが、Active Jobはこれらのアダプタとなって動作します。
Active Jobは、ジョブスケジューリングを抽象化するAPIを備えており、異なるジョブ実行の仕組みに移行(たとえばDelayed JobからResqueへ移行)しても、コードをほとんど変えることなく実行することができます。
Active Jobを使うための準備
Resqueのセットアップ
今回はActive JobをResqueのアダプタとして使用するので、Resqueをセットアップします。
Resqueは、Redisが必要なのでインストールを済ませておきます。
MacでHomebrewを利用している場合は、以下のようにしてインストールします。
$ brew install redis
次にResqueをセットアップします。
以下のようにGemfileに指定して、bundle install
を実行します。
gem 'resque'
gem 'resque-scheduler'
インストールできたら、初期設定ファイルとrakeタスクの追加を行います。
Resque.redis = Redis.new(host: 'localhost', post: 6379)
Resque.after_fork = Proc.new { ActiveRecord::Base.establish_connection }
Reqeustの設定ファイルを以下の内容で作成します。
require 'resque/tasks'
require 'resque/scheduler/tasks'
namespace :resque do
task setup: :environment do
ENV['TERM_CHILD'] ||= '1'
ENV['QUEUE'] ||= '*'
require 'resque'
require 'resque-scheduler'
end
end
Active Jobのセットアップ
以下のような初期設定ファイルを作成し、queue_adapter
としてResqueを指定します。
ActiveJob::Base.queue_adapter = :resque
Active Jobを実際に使ってみる
例として、Active Jobを使ってバックグラウンドでメールを送信してみます。
Webサービスで、ユーザーが登録した際にWelcomeメールを送信することを考えます。(今回は、Rdailyというブログ用のアプリケーションを使っています)
メーラの作成
以下のコマンドでUserMailer
を作成します。
$ rails g mailer user_mailer
送信用のメソッドとビューを追加します。
class UserMailer < ActionMailer::Base
default from: "from@example.com"
def registered(user)
mail(to: user.email, subject: 'Welcome to Rdaily!')
end
end
Dear. <%= @user.name %>
Welcome to Rdaily!
ジョブの作成
メーラを作成したので、次はActive Jobのジョブを作成します。
Rails 4.2ではActive Jobの導入に伴い、以下のようなジェネレータが利用できるようになっています。
$ rails g job user_registered_mailer
...
create app/jobs/user_registered_mailer_job.rb
作成されたファイルを以下のように編集します。
class UserRegisteredMailerJob < ActiveJob::Base
queue_as :email
def perform(user)
UserMailer.registered(user).deliver_now
end
end
アプリケーション内でのジョブの使用
作成したジョブを利用するには、コントローラなどで以下のようにジョブのインスタンスを作成し、待ち時間を指定して#perform_later
メソッドを呼び出します。
今回のアプリケーションの例では、ユーザーを作成後に以下のように呼び出しています。
class Account::UsersController < ApplicationController
...
def create
@user = User.new(user_params)
if @user.save
UserRegisteredMailerJob.perform_later(@user)
flash.notice = "User is successfully created."
redirect_to account_path
...
end
(追記)ActiveJob::Baseのサブクラスを定義することなく、
UserRegisteredMailerJob.perform_later(@user)
の部分を
UserMailer.registered(@user).deliver_later!(wait: 1.minute)
と直接メーラから#deliver_later!
メソッドで遅延して送信するジョブを登録することもできるようです。
ジョブの実行
メールの送受信をテストする前に、mailcatcherと呼ばれるgemをセットアップします。
Gemfile
に以下の記述を追加し、bundle install
を実行します。
gem 'mailcatcher'
環境設定ファイルに以下のように記述します。
Rails.application.configure do
...
config.action_mailer.delivery_method = :smtp
config.action_mailer.smtp_settings = { address: 'localhost', port: 1025 }
...
end
以下のコマンドでmailcatcherを起動します。
$ mailcatcher
各種サーバーを起動します。(ログを参照するためにそれぞれターミナルの別タブで開きます)
Redisサーバーを以下のコマンドで起動します。
$ redis-server
Resqueのワーカーを以下のコマンドで起動します。
$ bundle exec rake resque:work
Resqueスケジューラを起動します。
$ rake environment resque:scheduler
最後にRailsサーバーを起動します。
$ rails server
ここでブラウザでユーザー登録のアプリケーションの操作を行います。
1分後に、Resqueスケジューラのログに
resque-scheduler: [INFO] 2014-10-09T22:53:15+09:00: Processing Delayed Items
mailcatcherのログに
==> SMTP: Received message from '<from@example.com>' (315 bytes)
と表示され、確かにジョブが実行されています。
まとめ
Rails 4.2に標準で含まれるActive Jobで簡単にジョブを登録して、バックグラウンドでスケジューリングしたジョブを実行することができるようになりました。