Madogiwa Blog

主に技術系の学習メモに使っていきます。

sidekiq pro / enterpriseのwikiを読んだので気になった機能の概要をMEMO✍

今回はタイトル通り、sidekiq pro / enterpriseのwikiを読んだので、忘れないように気になった機能の概要をメモしておきます✍

⚠私が拙い英語力 + 技術力で理解した内容のMEMOです。内容が間違っている可能性があるので、注意してください。⚠

前提事項

整理した内容は、2019/04/30現在のsidekiqのwikiに記載されている内容です。

Home · mperham/sidekiq Wiki · GitHub

sidekiq pro

Batches

https://github.com/mperham/sidekiq/wiki/Batches

Batchとして複数のJobの実行をまとめられる機能。
※概要は下記のコードを参照

# Batchの作成
batch = Sidekiq::Batch.new
# Batchの説明
batch.description = "Batch description (this is optional)"
# Callbacks
# `:success`: すべてのJobが成功して完了
# `:complete`: いくつかのJobが失敗を含んで完了
batch.on(:success, SomeClass, 'uid' => current_user.id)
batch.on(:complete, 'AnotherClass#method', 'uid' => current_user.id)
# BatchにJobを登録
# MEMO: Batchは1つ以上のJobを持たなければならない
# https://github.com/mperham/sidekiq/wiki/Batches#notes
batch.jobs { rows.each { |row| RowWorker.perform_async(row) } }
puts "Just started Batch #{batch.bid}"

class SomeClass
  def on_complete(status, options)
    puts "Uh oh, batch has failures" if status.failures != 0
  end
  def on_success(status, options)
    puts "#{options['uid']}'s batch succeeded.  Kudos!"
  end
end

Sidekiq::Batch.newでBatchのインスタンスを作成し、Sidekiq::Batch#jobsのブロック内でWorker.perform_asyncを呼び出すことで、BatchにJobを登録することが出来る。

またSidekiq::Batch#onsuccess(成功)complete(完了※失敗を含む)した場合のCallbackを登録することが出来る。

下記の例のような複雑なWorkflowを組むことも出来る👀

Reliability

https://github.com/mperham/sidekiq/wiki/Reliability

sidekiqの信頼性を向上される機能。大きく分けて2つの機能が提供される。

  • super_fetch: Jobが完了するまでRadisのqueueを削除しない機能、もしもsidekiqのprocessが落ちて再起動した or 前回の走査から1時間経過した場合は、Redisのqueueをフルスキャンし、queueを再実行する。
  • reliable_scheduler: より信頼性の高いschedule実行機能、Redisからjobをpopして実行してくれる。(sidekiq proではLuaを使って、より信頼性の高いスケジューラ)を提供してくれるらしい。※このへんはよく分かってない・・・。

有効にするためにはinitializers/sidekiq.rb内で下記を実行する。

Sidekiq::Client.reliable_push! unless Rails.env.test?

Sidekiq.configure_server do |config|
  config.super_fetch!
  config.reliable_scheduler!
end

Client-side Reliability

https://github.com/mperham/sidekiq/wiki/Pro-Reliability-Client

sidekiqのClient側で信頼性を向上させる機能。具体的には、最初にメモリ上のqueueにpushし、RedisへのNetwork接続が確立されてから、Redisへqueueのpushを行う機能。

有効にするためにはinitializers/sidekiq.rb内で下記を実行する。

Sidekiq::Client.reliable_push! unless Rails.env.test?

Expiring Jobs

https://github.com/mperham/sidekiq/wiki/Pro-Expiring-Jobs

一定期間後に無効化されるJobを作成する機能。

有効にするためにはinitializers/sidekiq.rb内で下記を実行する。

require 'sidekiq/pro/expiry'

Worker内で、sidekiq_options expires_in: 1.hourとするとJobの有効期間を1時間にすることが出来る。(1時間以内に実行されなければ、もう実行しない。)

class SomeWorker
  include Sidekiq::Worker
  sidekiq_options expires_in: 1.hour
  ...
end
# 実行時に指定する場合
SomeWorker.set(expires_in: 1.day).perform_async(...)

※Batchに含まれているJobがexpiredされた場合は、成功とみなされるため注意する。

sidekiq enterprise

Rolling Restarts

https://github.com/mperham/sidekiq/wiki/Ent-Rolling-Restarts

sidekiqのRolling Restartを行う機能。sidekiqのrolling restartには、einhornというprocessマネージャーを使用する。

  • einhornsh --execute upgradeがrolling restartのトリガーとなるので、デプロイ後等、プログラムが置き換わったあとに実行するようにする。
  • 新しいprocessが立ち上がってから10秒後に、まだ古いprocessが起動してたらUSR2を送って古いprocessを正常に終了させてくれる。

Rate Limiting

https://github.com/mperham/sidekiq/wiki/Ent-Rate-Limiting

Jobの実行を制限するような機能を使える。制限はSidekiq::Limiterを使って追加する。

Concurrent

Jobの同時実行数を制限する機能。Sidekiq::Limiter.concurrentで制限する。下記例では、同時実行数は50に制限される。

ERP_LIMIT = Sidekiq::Limiter.concurrent('erp', 50, wait_timeout: 5, lock_timeout: 30)

def perform(...)
  ERP_LIMIT.within_limit do
    # call ERP
  end
end

Bucket, Window

指定期間内での実行数を制限する機能。Sidekiq::Limiter.bucketSidekiq::Limiter.windowで提供される。 c

# Bucketc
# 下記例では、1秒あたりに30回までと実行が制限される
def perform(user_id)
  user_throttle = Sidekiq::Limiter.bucket("stripe-#{user_id}", 30, :second, wait_timeout: 5)
  user_throttle.within_limit do
    # call stripe with user's account creds
  end
end

# Window
# 下記例では、5秒間に1回までになる?Windowはよくわからなかった。。。
def perform(user_id)
  user_throttle = Sidekiq::Limiter.window("stripe-#{user_id}", 5, :second, wait_timeout: 5)
  user_throttle.within_limit do
    # call stripe with user's account creds
  end
end

bucketとwindowの違いがわからん。。。

Unlimited

既存の制限を外す機能。Sidekiq::Limiter.unlimitedで提供される。 ※管理ユーザだけ制限を解除するような用途で使用する。

ERP = Sidekiq::Limiter.concurrent("erp", 10)

def perform(...)
  lmtr = current_user.admin? ? Sidekiq::Limiter.unlimited : ERP
  lmtr.within_limit do
    # always executes for admins
  end
end

Periodic Jobs

https://github.com/mperham/sidekiq/wiki/Ent-Periodic-Jobs

Jobの定期実行機能。
initializers/sidekiq.rb内で下記のようにcrontab形式でスケジュールを定義出来る。※WebUIでも一覧を確認出来る。

Sidekiq.configure_server do |config|
  config.periodic do |mgr|
    # see any crontab reference for the first argument
    # e.g. http://www.adminschoice.com/crontab-quick-reference
    # or   https://crontab.guru/ 
    mgr.register('0 * * * *', SomeHourlyWorkerClass)
    mgr.register('* * * * *', SomeWorkerClass, retry: 2, queue: 'foo')
    mgr.register(cron_expression, worker_class, job_options={})
  end
end

Unique Jobs

一意になるようなJob(Redis内に複数のqueueが存在しないようなJob)を定義することが出来る機能。

有効にするためにはinitializers/sidekiq.rb内で下記を実行する。

Sidekiq::Enterprise.unique! unless Rails.env.test?

Workerを下記のように定義すると、10分後または、Jobが正常に処理された際に次回のJobがqueueにpushされる。

class MyWorker
  include Sidekiq::Worker
  sidekiq_options unique_for: 10.minutes

  def perform(...)
  end
end

おわりに

今回はsidekiq proとenterpriseで提供される機能で私が気になったものを整理してみましたm( )m

proのBatchやReliabilityの機能は、プロダクト運用で有用そうなので、ビジネスで利用するときは使うと良さそうな機能ですね👀

enterpriseもRolling RestartsやPeriodic Jobsなど、かゆいところに手が届く機能が多く良さそうに見えました👀

みなさんも気になったら詳しい内容が公式Wikiに記載されてるので、読んでみてくださいー。

Home · mperham/sidekiq Wiki · GitHub

それでは👋