Heroku + Redis + Resque + ActiveJobで手軽に無料でバックグラウンド処理

# 概要
* 2015/05のHerokuの料金体制改定で、Freeプランでもworker dynoが使えるようになった。
* さらに、2015.06にはHeroku Redisが一般公開された。25MBまでなら無料で使える。
* Rails 4.2で追加された`ActiveJob`の機構を使って、シンプルに、効率的に無料でHeroku上でバックグランド処理を実装できるようになった。

# 背景知識
## Heroku
* Herokuにはweb dynoとworker dynoがある。
  * HTTPリクエストを処理するのがweb dyno
  * バックグランドで処理をするのがworker dyno
  * 元々の無料プランではweb dynoの追加には料金がかかったが、新しい無料プランでは制限付きながらworker dynoが使えるようになった。実験するには、それでも十分。
* Heroku上でバックグランド処理をやる仕組みとしては`Delayed Job`というものが用意されていたが、 DBの負荷的な問題から現在は使用が[推奨されていない](https://devcenter.heroku.com/articles/delayed-job)。
  * 代わりにRedisベースのキューイングライブラリの使用が推奨されている。(`Resque`など)

## Redis、Resque
### Resque Scheduler
* Resque単体では、キューに積まれたジョブを順次実行していくことしかできないが、`Resque Scheduler`を使うと、任意のタイミングでジョブを実行できるようになる。
* 具体的には、「数日後にメールを送りたい」というようなジョブのスケジューリングが可能になる。
* ややこしくなるため、`Resque Scheduler`の説明はここでは割愛。

## ActiveJob
* Rails 4.2で登場した、バックグラウンドジョブの実行機構。
* Delayed JobとResqueなどのように、さまざまなジョブ実行機能のAPIの違いを気にせずにバックグラウンドジョブの実装を記述できる。

# ステップ
1. 開発環境のセットアップ
2. Herokuの設定
+ ローカルで動かす
+ Heroku上で動作確認

# 開発環境のセットアップ
## Redisのインストール

```
brew install redis
```

必要に応じて、自動起動の設定を行う。(インストール後のメッセージに表示される)

# 開発時
## Resqueの設定
### gemの追加
```:Gemfile
gem 'resque'
```

gemを追加するだけでOK。追加したら`bundle install`を実行する。

### Resqueの設定
```rb:config/initializers/resque.rb
Resque.redis = Redis.new(:url => ENV['REDIS_URL'])
Resque.after_fork = Proc.new { ActiveRecord::Base.establish_connection }
```

イニシャライザ`config/initializers/resque.rb`を作成して、接続先のRedisの設定と、ジョブ内でActiveRecordを使えるようにするための設定を行う。

Heroku RedisでRailsからRedisを使う場合は、`url`に`ENV['REDIS_URL']`を指定する。(https://devcenter.heroku.com/articles/heroku-redis#connecting-in-ruby)
環境変数`REDIS_URL`は、Heroku Redisアドオンを追加したタイミングでセットされる。当然、ローカルで実行した場合はurlが空となるので、Redisサーバーがデフォルト以外の場所で動いている場合は別途指定が必要。

fork後に`ActiveRecord::Base.establish_connection`を実行して、ActiveRecordが使えるように設定している。

### ActiveJobでResqueを使うように設定
```rb:config/initializers/active_job.rb
ActiveJob::Base.queue_adapter = :resque
```

同じく、`ActiveJob`用のイニシャライザを作成し、その中で`queue_adapter`に`:resque`を指定する。

### Resque起動用タスクの追加

```rb:lib/tasks/resque.rake
require 'resque/tasks'
```

## Resqueの起動

```
TERM_CHILD=1 QUEUES=* rake environment resque:work
```

`TERM_CHILD=1`をつけないと、`WARNING: This way of doing signal handling is now deprecated.`という警告が表示される。これは、Resqueの元々の実装で、プロセスを終了させるためのシグナルを受け取った際の仕様に問題があったため。互換性の問題のためデフォルトの挙動は古い仕様のままになっているが、現在ではその仕様は非推奨となっているためこのメッセージが表示される。`TERM_CHILD=1`をつけると一般的な、他のプログラムと同じ終了の挙動になり、警告も消える。

http://hone.herokuapp.com/resque/2012/08/21/resque-signals.html

# 実装
## Jobクラスを作る

```
rails g job my_job
```

```
class MyJob < ActiveJob::Base
  queue_as :default

  def perform(instance)
    p "Process #{instance}"
  end
end
```

## 非同期処理をキューに積む

```
MyJob.perform_later(instance)
```

# Herokuの設定
## Heroku Redisの追加

https://elements.heroku.com/addons/heroku-redis からプランを選択して追加する。25MBまでなら無料のHobbyプランが使える。Hobbyプランでは永続化はできないが、Resqueで使う分には大きな問題はない。(Redisが再起動した時にその時のキューの内容が消えてしまうという問題はあるかもしれない)

## Worker用プロセスの設定
```rb:Procfile
worker: TERM_CHILD=1 QUEUES=* rake environment resque:work
```

Resque用のRakeタスクをWorkerとして起動させるように設定。

## Workerの有効化
![スクリーンショット 2015-10-20 13.43.53.png](https://qiita-image-store.s3.amazonaws.com/0/14097/af8adb7d-ba54-d4e9-78a6-579b1b93381d.png)

最後に、ダッシュボード上からWorkerを有効化して完成。

# 結論
Herokuのプラン改定、Heroku Redisの登場、Active Jobの登場によって、Heroku上でのバックグラウンド処理の実装がとても身近になった。どんどん活用しよう。

# 参考リンク
* http://blog.flect.co.jp/labo/2015/05/free-dyno-fae3.html
* https://devcenter.heroku.com/articles/delayed-job
* https://blog.engineyard.com/2014/getting-started-with-active-job
* http://qiita.com/Takayuki-Suzuki@github/items/cf2f904873496ff6c384