$ ruby -v
ruby 2.0.0p353 (2013-11-22 revision 43784) [x86_64-darwin13.0.0]
$ padrino -v
Padrino v. 0.11.4
$ sidekiq -V
Sidekiq 2.17.0
準備
Sidekiq はジョブキューの管理に Redisを使うのでインストールしておきます
インストール方法は割愛(mac なら brew install redis
とか)
$ redis-server -v
Redis server v=2.8.1 sha=00000000:0 malloc=libc bits=64 build=b8cc45f60db4b294
あとは適当に Padrino プロジェクトを作成したり既存の Padrino プロジェクトに移動します
$ padrino g project sidekiq_with_padrino_sample -d minirecord -t rspec
$ cd sidekiq_with_padrino_sample
インストール
$ vim Gemfile
gem 'sidekiq'
$ bundle install
もし Bundler could not find compatible versions for gem "activesupport":
のようなエラーが出た場合は Gemfile におまじないを追記します
gem 'activesupport’, '>= 3.2', '< 4.0'
Worker
workerを追加する
バックグラウンドで働かせたいクラスを workers ディレクトリ以下に配置して管理する方針で進めます
$ mkdir workers
$ vim worders/hard_worker.rb
class HardWorker
include Sidekiq::Worker
def perform(name, count)
raise name if name == 'crash'
logger.info "Doing hard work: #{name}"
sleep count
end
end
workerを使う
上で作った hard_worker をコントローラの中で使ってみます
$ bundle exec padrino g controller sample get:index
$ vim app/controllers/sample.rb
SidekiqWithPadrinoSample::App.controllers :sample, map: '/' do
get :index do
@count = rand(10)
logger.info "Adding #{@count} jobs"
@count.times do |i|
HardWorker.perform_async("Job_#{i}", 1)
end
end
end
では動かしてみます
$ bundle exec padrino s
$ curl localhost:3000
INFO - Adding 4 jobs
NameError - uninitialized constant HardWorker:
worker が読み込めてないのでエラーになります
config/boot.rb を編集して workers ディレクトリの中身を読み込むようにします
Padrino.before_load do
Padrino.require_dependencies Dir[Padrino.root('workers', '**', '*.rb')]
end
再度確認
$ bundle exec padrino s
$ curl localhost:3000
INFO - Adding 5 jobs
$ redis-cli
127.0.0.1:6379> LLEN queue:default
(integer) 5
ちゃんとキューに入ってるっぽいですね
sidekiqを起動してジョブを実行させる
このままだとジョブがキューに溜まったままで実行されないので sidekiq コマンドを叩いてジョブを処理させます
$ bundle exec sidekiq -r ./config/boot.rb
HardWorker JID-964a803489a72625b4a4562b INFO: start
HardWorker JID-964a803489a72625b4a4562b INFO: Doing hard work: job_1
HardWorker JID-43088873fa56b66813c5e6db INFO: start
HardWorker JID-43088873fa56b66813c5e6db INFO: Doing hard work: job_0
HardWorker JID-4425acb6e3b41d96b1b9c6b5 INFO: start
HardWorker JID-4425acb6e3b41d96b1b9c6b5 INFO: Doing hard work: job_2
HardWorker JID-a190428084bd67332ff6114e INFO: start
HardWorker JID-a190428084bd67332ff6114e INFO: Doing hard work: job_3
HardWorker JID-2cc0feff0ee5880daab2558f INFO: start
HardWorker JID-2cc0feff0ee5880daab2558f INFO: Doing hard work: job_4
HardWorker JID-43088873fa56b66813c5e6db INFO: done: 1.001 sec
HardWorker JID-964a803489a72625b4a4562b INFO: done: 1.004 sec
HardWorker JID-a190428084bd67332ff6114e INFO: done: 1.002 sec
HardWorker JID-2cc0feff0ee5880daab2558f INFO: done: 1.001 sec
HardWorker JID-4425acb6e3b41d96b1b9c6b5 INFO: done: 1.004 sec
キューに入っていたジョブのログがドドッと出力されます
ActiveRecord
確認用のモデルを作る
$ bundle exec padrino g model post title:string body:text
$ vim models/post.rb
class Post < ActiveRecord::Base
# Fields
field :title, :as => :string
field :body, :as => :text
def long_method
puts "#Long method [#{self.id}] start"
sleep 5
puts "#Long method [#{self.id}] finished"
end
end
ActiveRecord 用の extension を設定する
Padrino.after_load do
# - omit -
ActiveRecord::Base.send(:include, Sidekiq::Extensions::ActiveRecord)
end
バックグラウンド実行してみる
Post#long_method
を sidekiq の delay メソッド経由で実行させます
get :delayed_post do
post = Post.where(title: 'First post', body: 'body').first_or_create
post.delay.long_method
'enqueued'
end
確認してみます
$ bundle exec padrino s
$ curl localhost:3000/delayed_post
enqueued
$ bundle exec sidekiq -r ./config/boot.rb
# Long method [1] start
# Long method [1] finished
できました
※この手順通りにやって unable to open database file
って怒られた場合は、手動で db ディレクトリを作ってみてください
Mailer
確認用のメーラーを作る
$ bundle exec padrino g mailer notifier greeting
$ vim app/mailers/notifier.rb
SidekiqWithPadrinoSample::App.mailer :notifier do
email :greeting do |now|
from 'sender@example.com'
to 'recipient@example.com'
subject 'Hello!'
locals now: now, hostname: `hostname`.strip
render 'notifier/greeting'
end
end
p Hi!, it's #{now} and I'm at #{hostname}.
メーラーの設定
確認用なので、実際にメールを飛ばさないように適当に設定しておきます
set :delivery_method, :test
メール送信ジョブをキューに溜める
get :email do
SidekiqWithPadrinoSample::App.delay_for(10.seconds).deliver(:notifier, :greetings, Time.now)
'enqueued'
end
$ bundle exec padrino s
$ curl localhost:3000/email
enqueued
sidekiq 起動用のファイルを用意する
require File.expand_path("../boot.rb", __FILE__)
# Loads the Padrino applications mounted within the project.
Padrino.mounted_apps.each do |app|
logger.info "=> Loading Padrino Application : #{app.app_class}"
app.app_obj.setup_application!
end
キューに溜まったジョブを実行させる
$ bundle exec sidekiq -r ./config/sidekiq.rb
…
DEBUG - Sending email to: recipient@example.com
…
できました
Monitoring
sidekiq/web
をマウントする
# Mount the Sidekiq monitoring application
require 'sidekiq/web'
Padrino.mount('Sidekiq::Web', app_class: 'Sidekiq::Web', app_root: Sidekiq::Web.root).to('/sidekiq')
おまじない
require 'sidekiq/web'
class Sidekiq::Web < ::Sinatra::Base
class << self
def dependencies; []; end
def setup_application!; end
def reload!; end
end
end
これでOK
$ bundle exec padrino s
$ open http://localhost:3000/sidekiq
ロガーの設定
Sidekiq.logger = Padrino.logger
開発環境等では非同期にしない
require 'sidekiq/testing/inline' if PADRINO_ENV == 'development'
テスト
RSpec を使っているのであれば rspec-sidekiq を使うのがいいのかな?
gem 'rspec-sidekiq', :group => 'test'
require 'spec_helper'
describe HardWorker do
it { expect(HardWorker).to be_processed_in :default }
end
この記事のコード
参考
https://github.com/mperham/sidekiq/pull/760/files
http://qiita.com/nysalor/items/94ecd53c2141d1c27d1f
http://qiita.com/mat_aki/items/840b63817ea858fa09b7