概要
今回は Rails 4.2 から新しく導入された Active Job という仕組みを利用して、メール送信の非同期処理を実現したいと思います。
Active Job とは
Rails 4.2 から Active Job が導入されました。
従来 Rails のジョブキュー処理には Resque, Delayed Job, Sidekiq などの Gem が使われてきましたが、Active Job はそれらをカプセル化してより抽象化したものです。
Active Job を利用する場合も依然として上に挙げた Gem のいずれかを導入する必要があるのですが、Active Job が提供する API を利用する場合は、それらはあくまでアダプタとなります。そして、アダプタがどのようなものであるかをほとんど意識することなくジョブキュー処理を利用できるわけです。
導入
今回は Active Job のアダプタには Sidekiq を採用したいと思います。
01. Redis のインストール
Sidekiq はバックエンドに Redis を利用するので導入しておきます。
Mac で Homebrew を利用している場合は、以下のコマンドでインストールできます。
$ brew install redis
02. Sidekiq のインストール
まず Gemfile に Sidekiq を追加して bundle install
します。
gem 'sidekiq', '~> 3.3.2'
$ bundle install
次に Rails の設定で、Active Job のキューアダプタとして Sidekiq
を使用することを宣言しておきます。
config.active_job.queue_adapter = :sidekiq
そして Sidekiq を起動する前に、あらかじめ Redis を起動しておきます。
$ redis-server
その後、Sidekiq を起動します。
$ bundle exec sidekiq -q default -q mailers
ここで1点ポイントがあります。後に Rails の Active Job と Action Mailer を利用してメールを非同期で送信することになり、その際に mailers
という名前のキューを用いるのですが、それを起動時に -q, --queue
オプションで指定しておく必要があります。
ただし、毎回オプションを指定するのも面倒です。そこで、設定ファイルを用意しておき、それを起動時に読み込むことにします。ついでにプロセスをデーモン化して、バックグランドで動作するようにしておきます。
:concurrency: 25
:pidfile: ./tmp/pids/sidekiq.pid
:logfile: ./log/sidekiq.log
:queues:
- default
- mailers
:daemon: true
$ bundle exec sidekiq -C config/sidekiq.yml
03. Action Mailer の作成
次は従来通り、Action Mailer クラスを作成します。
$ bundle exec rails g mailer honoka_mailer
class HonokaMailer < ActionMailer::Base
default from: 'honoka@example.com'
def yell_for(user)
mail(to: user.email, subject: 'ファイトだよっ!')
end
end
実行
では rails console
で実際にメール送信を試してみましょう。
まず、非同期ではなく即時にメールを送信する場合は、従来の ActionMailer::Base#deliver
の代わりに ActionMailer::MessageDelivery#deliver_now
を使用します (deliver メソッドは deprecated となっています) 。
kotori = User.find_by(name: '南 ことり')
HonokaMailer.yell_for(kotori).deliver_now
次に、非同期で送信する場合は、ActionMailer::MessageDelivery#deliver_later
を使用します。すると Active Job が自動的にジョブを登録してくれます。
umi = User.find_by(name: '園田 海未')
HonokaMailer.yell_for(umi).deliver_later
ジョブの実行を遅延させたい場合は引数で実行タイミングを指定することも可能です。
eri = User.find_by(name: '絢瀬 絵里')
HonokaMailer.yell_for(eri).deliver_later(wait: 1.minute) # 1分後に送信
niko = User.find_by(name: '矢澤 にこ')
HonokaMailer.yell_for(niko).deliver_later(wait_until: 5.minutes.from_now) # 時刻を指定して送信 (この場合は現在時刻から5分後)
これでメールの非同期送信もバッチリ! ✌ ('ω' ✌ )三 ✌ ('ω') ✌ 三( ✌ 'ω') ✌
おまけ… MailCatcher でテスト送信したメールの確認をする
開発環境などでメール送信のチェックをする際に MailCatcher というツールを利用すると便利です。
MailCatcher は簡易的な SMTP サーバとして機能し、Web GUI (gemspec ファイルを見るに Sinatra ベースっぽい) も備えていてそれを利用して送信したメールの内容確認もできます。
導入
まず MailCatcher をインストールします。
この時重要なのが、Rails プロジェクトの Gemfile に追加して bundle install
するのではなく、gem install
して追加するということです。
理由は README.md に以下のように書かれていました。
Please don't put mailcatcher into your Gemfile. It will conflict with your applications gems at some point.
$ gem install mailcatcher
次に Rails の開発環境の設定ファイルで Action Mailer 周りの設定を以下のように記述します。
# MailCatcher (http://mailcatcher.me/) を利用することを前提としている。
config.action_mailer.delivery_method = :smtp
config.action_mailer.smtp_settings = {
address: 'localhost',
port: 1025
}
あとは mailcatcher
コマンドで MailCatcher を起動して、Rails でメール送信を実行するだけです!
$ mailcatcher
http://127.0.0.1:1080/ で Web GUI にアクセスできます。