Sidekiq with Padrino

  • 20
    いいね
  • 0
    コメント
この記事は最終更新日から1年以上が経過しています。

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