[Ruby on Rails]Active Job – Sidekiqを使ってのJobの実行
はじめに
先日、Ruby on Rails 4.2がリリースされました。このリリースで新たに追加された機能にActive Jobがあります。今回はActive Jobについての簡単な説明と、実際に動かしてみたソースについて書きたいと思います。
Active Jobとは
Active Jobについて、Rails Guideより以下の文を引用します。
Active Job is a new framework in Rails 4.2. It is a common interface on top of queuing systems like Resque, Delayed Job, Sidekiq, and more.
Ruby on Rails 4.2 Release Notes
Active Jobは一言で表すと、「キューを実現するためのインターフェース」と言えると思います。あくまで「インターフェース」であるので、Active Job単体ではキューを実現することはできません。以下のキューイングシステムを呼び出すことで、キューを実現します。
- Delayed Job
- Qu
- Que
- queue_classic
- Resque 1.x
- Sidekiq
- Sneakers
- Sucker Punch
Active Jobの実装
では、実際にActive Jobを動かすソースについてです。タイトルに書いた通り、今回はSidekiqをキューイングシステムとして使用しました。以下、Active Jobを実行した際の手順とソースです。
1.プロジェクト作成
Rails 4.2を使用するため、Gemfileにバージョンを指定してbundle installを行います。
gem 'rails', '4.2.0'
$ rails new でプロジェクトを作成後、Gemfileにsidekiqを追加してbundle installします。
gem 'sidekiq'
尚、sidekiqはキューを実現するためRedisを使用するので、予めインストールしておいてください。
2.sidekiq.ymlの作成
sidekiqの設定を/config/sidekiq.ymlに記述しました。以下のようになります。
sidekiqの定義ファイル
:concurrency: 25 :pidfile: ./tmp/pids/sidekiq.pid :logfile: ./log/sidekiq.log :queues: - default
3.application.rb
Active Jobがsidekiqを使用することを、/config/application.rbに定義します。以下の行を追加します。
/config/application.rb
config.active_job.queue_adapter = :sidekiq
4.Jobの作成
Active Jobではキューに入れて実行したい処理を「Job」と呼んでいます。JobはRailsのGeneratorで作成することができます。今回は「MyJob」という名前でJobを作成しますが、Generatorは指定した名前に「Job」というプレフィックスをつけるため、以下のようなコマンドとなります。
$ bundle exec rails g job My
/app/jobs/my_job.rb が作成されるので、以下のように編集します。
/app/jobs/my_job.rb
class MyJob < ActiveJob::Base queue_as :default def perform(message) Task.new.exec(message) end end [/ruby] Jobは「ActiveJob::Base」を継承しています。このJobにて実行したい処理は「perform」メソッドとして実装します。今回は引数を受け取り、それを後述するTask.execに渡すだけを行っています。 </p> <h3>4.Taskクラス</h3> <p> Jobから呼び出されるTaskクラスです。今回は/app/models/task.rbに記述しました。 <h5>/app/models/task.rb</h5> class Task def exec(message) Rails.logger.info(message) end end
見ての通り、引数で受け取ったメッセージをログに出力しています。
5.Jobの呼び出し
Jobの呼び出しはControllerから行うことにしました。
/app/controllers/start_controller.rb
class StartController < ApplicationController def run # 即時実行する場合 MyJob.perform_later('Task exec.') # 時間を置いて実行する場合 MyJob.set(wait: 10.second).perform_later('Task exec 1.') MyJob.set(wait: 10.second).perform_later('Task exec 2.') render :nothing => true end end
Jobを実行する場合は、対象のJobクラスの「perform_later」メソッドを呼び出します。ソースに書いてある通り、引数を渡すことも可能です。「perform_later」メソッドが呼び出されると、Active JobはキューにJobを登録し、SidekiqがJobを実行します。またJobは即時に実行することも、時間を置いて実行することも可能です。
ルーティングの定義
上記のControllerを呼び出せるよう、/config/routes.rbに以下を記述します。
/config/routes.rb
post 'start/run'
Active Jobの実行
上記で実装したActive Jobを実行してみます。
まずはRedisを起動します。
$ redis-server
別のターミナルにて、sidekiqを起動します。
$ bundle exec sidekiq
また別のターミナルにて、Railsを起動します。
$ bundle exec rails s
Jobが起動し、Taskクラスから出力されるログが見れるよう、予めtailにてログファイルを監視しておきます。
tail -f log/development.log
curlにてControllerを呼び出します。
curl http://localhost:3000/start/run -X POST -d ''
curlコマンドの実行後、まずは即座に実行されるJobが起動し、以下がログに出力されます。
[ActiveJob] [MyJob] [0298f473-5bd7-4715-9c73-b64aef2a7e6f] Task exec.
しばらくした後、時間を置いて実行するよう指定したJobが起動し、以下がログに出力されます。
[ActiveJob] [MyJob] [dbb4bd39-62f8-459c-ae47-a88a07326ff6] Task exec 1. (中略) [ActiveJob] [MyJob] [b31c8007-40a8-4dfb-b7fd-503903f3f47f] Task exec 2.
まとめ
Active Jobを使った簡単なキューの実装でした。Active Jobを使うことで、どのキューイングシステムを使ってもソースに差が出にくくなります。
またActive Jobにはキューの優先付けや、CallBackなどの仕組みもあるようです。それらについても、今後書いていければと思います。
参考サイト
Active Job adapters
Ruby on Rails 4.2 Release Notes
Active Job Basics
Active Job -- Make work happen later