Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Rails Async Process with Sidekiq

wtnabe
August 29, 2015

Rails Async Process with Sidekiq

『Railsで非同期処理 - Sidekiqを使うための準備と使ってみて気づいたこと』 via Kanazawa.rb meetup #36

wtnabe

August 29, 2015
Tweet

More Decks by wtnabe

Other Decks in Programming

Transcript

  1. Railsで⾮同期処理
    Sidekiqを使うための準備と
    使ってみて気づいたこと
    @wtnabe
    Kanazawa.rb meetup 36
    2015-08-29 (Sat) at IT-Plaza MUSASHI

    View full-size slide

  2. お品書き
    ⾮同期処理とは
    Sidekiq
    ⾮同期Worker作成時の注意
    課題はテスト

    View full-size slide

  3. ⾮同期処理とは

    View full-size slide

  4. Railsで⾮同期処理とは
    HTTP requestと同期しないもの
    ジョブの実⾏指定と実際の実⾏時間が同
    期しないもの
    伝統的なバッチジョブは違う?
    クライアントサイドの⾮同期処理とは意味が違う

    View full-size slide

  5. 例えば
    POST時の処理を後回しに
    メールの送信
    画像のサムネイル⽣成
    response time短縮向け
    ⼤量の作業をスケジュール実⾏

    View full-size slide

  6. ⾮同期⽤のGem
    Rails 4.2+ ActiveJob ( adaptor )
    Rails 4.1- (various methods)
    DelayedJob
    BackgrounDrb
    Rescue
    Sidekiq

    View full-size slide

  7. Sidekiqの特徴
    http://sidekiq.org/
    Queue ⽤のストレージは Redis
    Celluloid を使ったスレッドモデル
    Sinatra 製の Dashboard 付き
    Sidekiq Pro アリ

    View full-size slide

  8. 今回選んだ理由
    もともとよく名前を⽬にしていた
    redis 環境の⽤意が楽になっていた
    Sidekiq Pro があるってことはビジネスを
    起こせるレベルのツールと看做せる
    Dashboard がレポートとしても使えそう

    View full-size slide

  9. セットアップ
    bundle install
    Procfile
    initializers/sidekiq.rb
    config/sidekiq.yml
    config/routes.rb ( if you wish Dashboard )

    View full-size slide

  10. Redisのインストールは省略

    View full-size slide

  11. bundle install
    in Gemfile
    gem 'sidekiq'

    View full-size slide

  12. Foremanの話はこちら
    前回 meetup #35 で紹介済み
    Lightweight PHP development environment with Foreman and built-in
    server // Speaker Deck

    View full-size slide

  13. Procfile
    Sidekiq⽤に別なRailsを⽴ち上げるイメージ
    web: bundle exec rails s
    redis: redis-server
    worker: mkdir -p tmp/pids && \
    bundle exec sidekiq \
    -C config/sidekiq.yml
    Unicornと同じように全部bundle execで済んじゃう

    View full-size slide

  14. Herokuでは初期化に注意
    RailsのバージョンによってDATABASE接
    続の設定反映の挙動が違う
    Herokuは環境変数設定を推奨している
    が、特にその辺りが違う
    see Advanced Options · mperham/sidekiq Wiki

    View full-size slide

  15. Concurrencyに注意
    RailsのDB connection poolはdefault 5
    Sidekiqのconcurrencyはdefault 25
    溢れるに決まってる><

    View full-size slide

  16. sidekiq.ymlの例
    :concurrency: 3
    :staging:
    :concurrency: 9
    :production:
    :concurrency: 9
    development は SQLite, production と staging で web と worker 2つの
    サーバから max 20 conn までの DB サーバに繋ぐ想定

    View full-size slide

  17. Dashboard
    in Gemfile
    gem 'sinatra'
    in routes.rb
    require 'sidekiq/web'
    mount Sidekiq::Web => '/sidekiq'
    もちろんアクセス制限は忘れないで>< 

    View full-size slide

  18. Sidekiq Dashboard Demo

    View full-size slide

  19. Workerの作り⽅

    View full-size slide

  20. in Gemfile
    gem 'sidekiq'

    View full-size slide

  21. in application.rb
    app/workers ディレクトリを
    作る
    autoload 対象に
    eager_load 対象に
    eager_load については ggl `rails thread'

    View full-size slide

  22. in foo_worker.rb
    class FooWorker
    include Sidekiq::Worker
    def perform(*args)
    end
    end

    View full-size slide

  23. How to use
    FooWorker.perform_async(arg1, ...)
    FooWorker.perform_in(time, arg1, ...)
    etc

    View full-size slide

  24. worker⽤のRails上で
    perform()が呼ばれる
    request を受けた Rails とは別な⼈であることに注意
    perform_in() を使うと遅延時間が指定できる

    View full-size slide

  25. Worker作成時の注意点

    View full-size slide

  26. 基本⽤語
    ここでは以下のように⾔葉を⽤いる
    Worker
    実際に⾮同期の動作を担当するclass
    ジョブ
    Workerが実⾏する⼀つ⼀つの処理

    View full-size slide

  27. 注意点
    perform() にはプリミティブを与える
    できるだけ細かくジョブを分ける
    ※ Rubyにはプリミティブなんて存在しないけど

    View full-size slide

  28. serializeしたオブジェクト
    じゃダメなの?

    View full-size slide

  29. オブジェクト渡し
    簡単だしDBに負担掛けない
    Queueの容量膨らむ
    安定してdeserializeできるとは限らない
    処理の記録の意味が分からない

    View full-size slide

  30. 処理の記録重要
    ⾮同期処理はいつ終わるか分からない
    「ポチッとやって結果を⽬視」みたいな
    やり⽅は通⽤しない

    View full-size slide

  31. Sidekiqの記録
    Workerの名前と引数がそのまま残る
    readableな名前と引数を使う

    View full-size slide

  32. class BulkThumbnailGeneratorWorker
    include Sidekiq::Worker
    def perform(k, id, attr, size)
    r = Object.const_get(k).find(id)
    ...
    end
    end
    例えば⼀括サムネイル⽣成

    View full-size slide

  33. こうすると
    どのModelの
    どのIDの
    どのカラムの画像を
    どのサイズにするのか
    これらが記録に残る。readableで丸分かり。

    View full-size slide

  34. しかも
    ⼩分けにできる

    View full-size slide

  35. ジョブの⼩分け重要
    × 1万回のeachのある1つのジョブ
    ○ 1万のジョブ
    ※ ⼩分けなら記録も明確で途中からretryできる

    View full-size slide

  36. ジョブの分け⽅
    ⼤量の作業が必要な場合
    peform の中で each しない
    each の中で perform_in を呼ぶ
    処理に掛かる時間を予測して遅延時間
    を指定しておく
    もちろん必要な遅延時間はあらかじめ予測して検証する

    View full-size slide

  37. 課題はテスト

    View full-size slide

  38. 今のところ⾃動テストなし
    そんなに変更しない
    いつも⾛らせる必要はない

    View full-size slide

  39. ⼤きな課題は
    peform の呼び⽅呼ばれ⽅のコードというよりは
    遅延時間やジョブの衝突などの⽅で、こ
    れは⾮常にテストしにくい

    View full-size slide

  40. (機会があれば)
    頑張ります><

    View full-size slide