Edited at

Sidekiq with Padrino

More than 1 year has passed since last update.

SidekiqPadrino で使う場合のメモです

$ 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


Gemfile

gem 'sidekiq'


$ bundle install

もし Bundler could not find compatible versions for gem "activesupport": のようなエラーが出た場合は Gemfile におまじないを追記します


Gemfile

gem 'activesupport’, '>= 3.2', '< 4.0'



Worker


workerを追加する

バックグラウンドで働かせたいクラスを workers ディレクトリ以下に配置して管理する方針で進めます

$ mkdir workers

$ vim worders/hard_worker.rb


workers/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


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 ディレクトリの中身を読み込むようにします


config/boot.rb

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


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 を設定する


config/boot.rb

Padrino.after_load do

# - omit -
ActiveRecord::Base.send(:include, Sidekiq::Extensions::ActiveRecord)
end


バックグラウンド実行してみる

Post#long_method を sidekiq の delay メソッド経由で実行させます


app/controllers/sample.rb

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


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



app/views/mailers/notifier/greeting.slim

p Hi!, it's #{now} and I'm at #{hostname}.



メーラーの設定

確認用なので、実際にメールを飛ばさないように適当に設定しておきます


app/app.rb

set :delivery_method, :test



メール送信ジョブをキューに溜める


app/controllers/sample.rb

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 起動用のファイルを用意する


config/sidekiq.rb

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をマウントする


config/apps.rb

# Mount the Sidekiq monitoring application

require 'sidekiq/web'
Padrino.mount('Sidekiq::Web', app_class: 'Sidekiq::Web', app_root: Sidekiq::Web.root).to('/sidekiq')

おまじない


lib/sidekiq-web.rb

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


ロガーの設定


config/boot.rb

Sidekiq.logger = Padrino.logger



開発環境等では非同期にしない


config/boot.rb

require 'sidekiq/testing/inline' if PADRINO_ENV == 'development'



テスト

RSpec を使っているのであれば rspec-sidekiq を使うのがいいのかな?


Gemfile

gem 'rspec-sidekiq', :group => 'test'



spec/workers/hard_worker_spec.rb

require 'spec_helper'

describe HardWorker do
it { expect(HardWorker).to be_processed_in :default }
end



この記事のコード

Github に置いてあります


参考

https://github.com/mperham/sidekiq/pull/760/files

http://qiita.com/nysalor/items/94ecd53c2141d1c27d1f

http://qiita.com/mat_aki/items/840b63817ea858fa09b7