34.Sidekiq

プロダクトに導入されているが、問題が多すぎて散々迷惑を被っているSidekiqについてお勉強。
今までは無料版を使っていたが、流石に酷すぎてProを導入する運びとなった。設定などはこれから。
(ただSidekiqそのものが悪いというよりは、よく分からないまま導入し使用されてきた点が問題な気がする)

Sidekiqとは

Railsアプリで非同期処理を行う為のライブラリ。

github.com

Simple, efficient background processing for Ruby.
Sidekiq uses threads to handle many jobs at the same time in the same process.
It does not require Rails but will integrate tightly with Rails to make background processing dead simple.

前提

・Redisが必要(なおRedisについては下記にまとめた)。 tnet.hatenadiary.com

使い方

github.com

補足

system.blog.uuum.jp

retry

プロセスでエラーが起きた時、
retry が有効な場合で、retry数がまだMAX retry数内(デフォルトは25)の場合は、ジョブ情報が retry queue に追加されます。
retry queue に保持される情報は、通常のジョブ情報に、エラー情報とリトライ回数などの情報が加えらえれたものになります。
上記で話した scheduledのキューを処理する poller は、retryのキュー情報も見るようになっているので、retryに入れられた情報は、
自然とジョブキューへ追加されます。

関連

qiita.com

Active Job は Rails におけるバックグラウンドジョブを動かすための共通インタフェースです。
バックグラウンドジョブを動かす Sidekiq、Resque、Delayed Job をアダプタとして利用できます。

Rails で提供されるのはジョブをメモリに保持するインプロセスのキューイングシステムだけなので Rails を再起動するとジョブは全て失われます。
(アダプタを指定しなかった場合のデフォルト動作)(参考)

Sidekiq Pro:通常版との違い

概観

selmertsx.hatenablog.com

TL;DR
sidekiq proでは、server processが死んでも jobの復活がサポートされる
sidekiq proにおいて、redis が死んでも、1000件程度のジョブならclientが保持し続けて、redisが復活したタイミングでenqueue してくれる
↑の状況において、client processが死ねば、蓄積された1000件のジョブは全て消える
sidekiq enterpriseでは、unique な jobになるように諸々やってくれるが、完全に保証してくれるものでは無いので、そこんところを考えたjob設計にすること。
Jobが失われないようにする仕組みについて
sidekiqにおいてjobが失われるケースは下記の3点

redisに接続できないケース
client processが死んだケース
server processが死んだケース
この中でSidekiq Proが対策をしているのは redisに接続できない と server processが死んだ の2つのケース。

Reliability

sidekiq.org

Enable more complex job workflows with Batches and Callbacks
Better server reliability in the face of Ruby VM crashes
Better client reliability in the face of Redis networking problems
Pause queues (e.g. only process a queue during business hours)
Expire unprocessed jobs after a deadline
Send job processing metrics to Statsd
High performance API extensions using Redis's Lua support
Search for jobs in the Web UI

Ruby VMとは
 RubyJavaなどの言語と同様、その言語用のVM仮想マシン)上で実行される。その仮想環境のこと。
 (なおCやGo言語などはマシン語コンパイルされ、VMではなくコンピュータが直接実行する。)

github.com

Setup
TL;DR To use the Reliability features in Sidekiq Pro, add this to your initializer:

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

Sidekiq.configure_server do |config|
  config.super_fetch!
  config.reliable_scheduler!
end
Using super_fetch
Sidekiq uses BRPOP to fetch a job from the queue in Redis. This is very efficient and simple but it has one drawback: the job is now removed from Redis. If Sidekiq crashes while processing that job, it is lost forever. This is not a problem for many but some businesses need absolute reliability when processing jobs.

Sidekiq does its best to never lose jobs but it can't guarantee it; the only way to guarantee job durability is to not remove it from Redis until it is complete. For instance, if Sidekiq is restarted mid-job, it will try to push the unfinished jobs back to Redis but networking issues can prevent this.

Sidekiq Pro offers an alternative fetch strategy, super_fetch, for job processing using Redis' RPOPLPUSH command which keeps jobs in Redis. To enable super_fetch:

Sidekiq.configure_server do |config|
  # This needs to be within the configure_server block
  config.super_fetch!
end

・BRPOPとは
 ・ブロッキングするリストのPOPプリミティブのこと。←?
  ・要は「データが入力されると、リストの右側から取り出して来る」方式のことを指すようだ。
  ・指定されたリストからPOPする要素が無いときは接続をブロックする(LPOPのブロッキング版)。
  ・要素は空ではない最初のリストの先頭からPOPされ、指定された順番で指定されたキーがチェックされる。

・上記を一部和訳 & 意訳 & 要約する。

BRPOP方式はシンプルで効率的だが、一度Sidekiqがクラッシュするとジョブが永遠に失われる。

ジョブが失われない様にする為には、完了するまでジョブの情報をRedisに残しておく必要がある。だが、基本的にこれは保証できない。
例えば何らかの要因でジョブが実行途中に中断され、中途半端な実行状態のジョブを再実行させようとした際、
SidekiqはそのジョブをRedisに戻そうとするが、ネットワーク上の障害によってそれが妨げられる可能性もある。

Sidekiq Proでは上記を解決する為の、代替的なジョブ取得方法を提案出来る。
それがsuper_fetchだ。Redisに対してRPOP LPUSHコマンドを用いる事でこれを実現する。