Edited at

秩序のないメール送信に Sidekiq (with Active Job)

More than 3 years have passed since last update.


概要

今回は 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 します。


Gemfile

gem 'sidekiq', '~> 3.3.2'


$ bundle install

次に Rails の設定で、Active Job のキューアダプタとして Sidekiq を使用することを宣言しておきます。


config/application.rb

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 オプションで指定しておく必要があります。

ただし、毎回オプションを指定するのも面倒です。そこで、設定ファイルを用意しておき、それを起動時に読み込むことにします。ついでにプロセスをデーモン化して、バックグランドで動作するようにしておきます。


config/sidekiq.yml

: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


app/mailers/honoka_mailer.rb

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 となっています) 。


pry

kotori = User.find_by(name: '南 ことり')

HonokaMailer.yell_for(kotori).deliver_now

次に、非同期で送信する場合は、ActionMailer::MessageDelivery#deliver_later を使用します。すると Active Job が自動的にジョブを登録してくれます。


pry

umi = User.find_by(name: '園田 海未')

HonokaMailer.yell_for(umi).deliver_later

ジョブの実行を遅延させたい場合は引数で実行タイミングを指定することも可能です。


pry

eri = User.find_by(name: '絢瀬 絵里')

HonokaMailer.yell_for(eri).deliver_later(wait: 1.minute) # 1分後に送信


pry

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 周りの設定を以下のように記述します。


config/environments/development.rb

# 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 にアクセスできます。


参考