LoginSignup
10
10

More than 5 years have passed since last update.

railsのActiveJobを使う

Last updated at Posted at 2015-09-24

Railsでバッググラウンドジョブを利用するための仕組みがActive Jobです。Active Jobを使えば、HTTPのメインスレッドでは応答を即座に返して、バックグラウンドで重い処理を実行できます。

ということで、早速設定します。Active Jobは基本的なバックグラウンドジョブを実行するための枠組みを提供するだけです。実際のバックグラウンドジョブを実行するバックエンドは設定で指定できます。バックエンドは複数あるようですが、sidekiqが現状のデファクトのようです。sidekiqはrailsとは別のプロセスで動作して、redisを介してジョブのやり取りを行います。簡易的なメッセージキューですね。

他にも有名なバックエンドにResqueというものものあるようですが、こちらもredisを介してジョブの実行を行いますが、redisが1.xでしかテストしてないとプロジェクトのページに書かれていたり、redisに対しては一定時間ごとにポーリングしてジョブの存在チェックをしているようです。ちょっと古臭いです。

インストール

redisとsidekiqをインストール・セットアップします。redisは、

$ brew install redis

で、インストールします。後は、

$ redis-server /usr/local/etc/redis.conf

でredisを起動します。

Rails側はGemfileに次の項目を追加して、インストールします

gem 'redis'
gem 'connection_pool'
gem 'sidekiq'
gem 'sinatra', require: false

config関係

前回の記事のように、redisの設定をします。

まずは、config/redis.ymlに次の記述をします

config/redis.yml
default: &default
  host: localhost
  port: 6379

development:
  <<: *default

test:
  <<: *default

production:
  <<: *default
  host: production-redis-server

次にsidekiqの設定を行うconfig/initializers/sidekiq.rbを次のようにします。

config/initializers/sidekiq.rb
# Load the redis.yml configuration file
redis_config = YAML.load_file(Rails.root + 'config/redis.yml')[Rails.env]

redis_conn = proc {
  Redis.new host: redis_config['host'], port: redis_config['port']
}
Sidekiq.configure_client do |config|
  config.redis = ConnectionPool.new(size: 5, &redis_conn)
end
Sidekiq.configure_server do |config|
  config.redis = ConnectionPool.new(size: 25, &redis_conn)
end

コネクションプールのサイズは決め打ちしていますが、redis.ymlで設定してもいいでしょう。

workerのファイルはapp/workersディレクトリに配置します。このディレクトリを自動で読み込むようにconfig/application.rbを設定します。
それと、バックエンドにsidekiqを使用するように設定します。

config/application.rb
config.autoload_paths << "#{config.root}/app/workers"
config.active_job.queue_adapter = :sidekiq

起動

設定が終わったら、railsと一緒にsidekiqを立ち上げます。

$ bundle exec sidekiq

オプションでログファイルを指定したり、デーモン化できます。productionで動かす時は-e productionをオプションに追加します。
workerは変更しても自動では再読み込みされないので、プロセスの再起動が必要です。

workerの設定

ジョブはworkerで指定します。次のコードは標準出力に出力するworkerです。

app/workers/print_worker.rb
class PrintWoker
  include Sidekiq::Worker

  def perform(s)
    print s
  end
end

引数で与えられた文字列を出力するだけです。workerの中ではActive Recordなども普通に扱えます。

ではworkerを実行させるためのrails側のコードです。controllerなどに次のように記述します。

PrintWorker.perform_async "Hello, World"

これだけで非同期にworkerが実行されます。performを直接実行すると、メインスレッドの中でそのまま実行できます。引数には文字列や数字などのプリミティブなものだけしか扱えないので、注意が必要です。

これ以外にも、指定した時間にジョブを実行させることや、数分後に実行など、ジョブを実行させるタイミングも制御できます。

ActionMailer

ActionMailerもActive Jobに対応しています。deliver_nowを実行していたものをdeliver_laterに変更するとバックグラウンドジョブとして非同期に実行されます。

sidekiqはデフォルトではdefaultのキューしか処理ません。メールキューを処理させるためには、次のコマンドで起動します。

$ bundle exec sidekiq -q default -q mailers
10
10
0

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
10
10