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

# <i class="fa fa-star fa-fw"></i>概要

今回は Rails 4.2 から新しく導入された [Active Job](http://railsguides.jp/4_2_release_notes.html#active-job) という仕組みを利用して、メール送信の非同期処理を実現したいと思います。

# <i class="fa fa-star fa-fw"></i>Active Job とは

Rails 4.2 から [Active Job](http://railsguides.jp/4_2_release_notes.html#active-job) が導入されました。
従来 Rails のジョブキュー処理には [Resque](https://github.com/resque/resque), [Delayed Job](https://github.com/collectiveidea/delayed_job), [Sidekiq](https://github.com/mperham/sidekiq) などの Gem が使われてきましたが、Active Job はそれらをカプセル化してより抽象化したものです。
Active Job を利用する場合も依然として上に挙げた Gem のいずれかを導入する必要があるのですが、Active Job が提供する API を利用する場合は、それらはあくまでアダプタとなります。そして、アダプタがどのようなものであるかをほとんど意識することなくジョブキュー処理を利用できるわけです。

# <i class="fa fa-wrench fa-fw"></i>導入

今回は Active Job のアダプタには Sidekiq を採用したいと思います。

## 01. Redis のインストール

Sidekiq はバックエンドに [Redis](http://redis.io/) を利用するので導入しておきます。
Mac で Homebrew を利用している場合は、以下のコマンドでインストールできます。

```
$ brew install redis
```

## 02. Sidekiq のインストール

まず Gemfile に Sidekiq を追加して `bundle install` します。

```:Gemfile
gem 'sidekiq', '~> 3.3.2'
```

```
$ bundle install
```

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

```ruby: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
```

```ruby: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
```

# <i class="fa fa-heart fa-fw"></i>実行

では `rails console` で実際にメール送信を試してみましょう。

まず、非同期ではなく即時にメールを送信する場合は、従来の `ActionMailer::Base#deliver` の代わりに `ActionMailer::MessageDelivery#deliver_now` を使用します (deliver メソッドは deprecated となっています) 。

```ruby:pry
kotori = User.find_by(name: '南 ことり')
HonokaMailer.yell_for(kotori).deliver_now
```

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

```ruby:pry
umi = User.find_by(name: '園田 海未')
HonokaMailer.yell_for(umi).deliver_later
```

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

```ruby:pry
eri = User.find_by(name: '絢瀬 絵里')
HonokaMailer.yell_for(eri).deliver_later(wait: 1.minute) # 1分後に送信
```

```ruby:pry
niko = User.find_by(name: '矢澤 にこ')
HonokaMailer.yell_for(niko).deliver_later(wait_until: 5.minutes.from_now) # 時刻を指定して送信 (この場合は現在時刻から5分後) 
```

これでメールの非同期送信もバッチリ！ ✌ ('ω' ✌ )三 ✌ ('ω') ✌ 三( ✌ 'ω') ✌ 

# <i class="fa fa-heart fa-fw"></i>おまけ… MailCatcher でテスト送信したメールの確認をする

開発環境などでメール送信のチェックをする際に [MailCatcher](https://github.com/sj26/mailcatcher) というツールを利用すると便利です。
MailCatcher は簡易的な SMTP サーバとして機能し、Web GUI (gemspec ファイルを見るに Sinatra ベースっぽい) も備えていてそれを利用して送信したメールの内容確認もできます。

## <i class="fa fa-wrench fa-fw"></i>導入

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

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

# <i class="fa fa-book fa-fw"></i>参考

* [Ruby on Rails 4.2 リリースノート](http://railsguides.jp/4_2_release_notes.html)
* [Rails 4.2で導入されたActive Jobを使ってみよう](http://qiita.com/ryohashimoto/items/2f8fd685920a5318def4)
* [Active Job · mperham/sidekiq Wiki](
https://github.com/mperham/sidekiq/wiki/Active-Job)