Article

ブログ

2015/05/13

Heroku Redis で Railsのセッションストアとバックグラウンドジョブ

こんにちは、本間です。

本日、Heroku が Heroku Redis として新アドオンを発表しましたので、早速利用してみることにしました。Herokuの新しい料金体系にて、バックグラウンドジョブが1プロセス無料になったことにより、RailsではActiveJobなどを利用してこのRedisをバックグラウンドジョブのキューとして気軽に利用できるようになりました。今回は簡単にその導入手順をまとめてみたいと思います。

セッションストアとしてのRedis

ご存知の通り、Railsのセッションはデフォルトでは Cookie に保存しており、こちらが毎度議論になるセキュリティの話になってきます。こちらの話は置いておいて、結局のところ、Redisのようなセッションストレージに保存しておけばこれら問題は解決できます。ですので積極的に利用していきましょう。

Railsのセッションストアの指定に移ります。まずはGemfileに以下を追加します。

gem 'redis'
gem 'redis-rails'

config/initializers/session_store.rb にはデフォルトでCookieの保存先を指定していますが、それを以下のようにRedisに保存させます。

Rails.application.config.session_store :redis_store, servers: ENV['REDIS_URL'], expire_in: 90.minutes

これだけでセッションをRedisに保存できるようになりました。

バックグラウンドジョブとしてのRedis

続いてはバックグラウンドジョブを実現してみます。Rails4.2 から導入されたActiveJobにアダプタとしてResque を利用します。

まずは Gemfileにgem 'resque' gem 'resque-scheduler'を追加します。

ResqueはRedisを利用しますので以下を追記。

Resque.redis = Redis.new(:url => ENV['REDIS_URL'])

Resque.after_fork = Proc.new { ActiveRecord::Base.establish_connection }

config/initializers/resque.rb

require 'resque/tasks'
require 'resque/scheduler/tasks'

namespace :resque do
  task :setup do
    require 'resque'
    require 'resque-scheduler'
    ENV['QUEUE'] ||= '*'
    Resque.before_fork = Proc.new { ActiveRecord::Base.establish_connection }
  end
end

lib/tasks/resque.rake

あとはActiveJobの記法に従ってバックグラウンドジョブを記述していくのみです。

ActionMailerも deliver_later として非同期処理にしてみましょう。

TERM_CHILD=1 QUEUE=default rake environment resque:work
bundle exec rails server

の2つを起動して、お互いが非同期処理のやりとりをできているかを確認します。

Heroku に適用

まずはじめに、新しい料金体系のFreeプランに変更し、Workerプロセスをオンにしましょう。

HerokuFreeプラン

早速、新アドオンを入れてみます。

heroku addons:create heroku-redis:test

まだtestですがそれでも今後間違いなくこちらはアップグレードされていきますし、何せHeroku公式のアドオンですから信頼できます。これでHerokuの環境変数 REDIS_URL が登録されます。

次にHeroku では Procfile と呼ばれるプロセス起動のための命令ファイルを記述します。web, worker それぞれ起動するタスクを記述します。webは今回はthinを利用しています。

web: bundle exec rails server thin -p $PORT -e $RACK_ENV
worker: TERM_CHILD=1 rake environment resque:work

以上でHerokuでWorker プロセスとの連携は完了です。重い処理は積極的にワーカープロセスで実行していくようにしましょう!