LoginSignup
48

More than 5 years have passed since last update.

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

Last updated at Posted at 2015-10-20

概要

  • 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の負荷的な問題から現在は使用が推奨されていない
    • 代わりにRedisベースのキューイングライブラリの使用が推奨されている。(Resqueなど)

Redis、Resque

Resque Scheduler

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

ActiveJob

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

ステップ

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

開発環境のセットアップ

Redisのインストール

brew install redis

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

開発時

Resqueの設定

gemの追加

Gemfile
gem 'resque'

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

Resqueの設定

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を使う場合は、urlENV['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を使うように設定

config/initializers/active_job.rb
ActiveJob::Base.queue_adapter = :resque

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

Resque起動用タスクの追加

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をつけると一般的な、他のプログラムと同じ終了の挙動になり、警告も消える。

実装

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用プロセスの設定

Procfile
worker: TERM_CHILD=1 QUEUES=* rake environment resque:work

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

Workerの有効化

スクリーンショット 2015-10-20 13.43.53.png

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

結論

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

参考リンク

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
48