らいむぎばたけ

つかまえなくてだいじょうぶ

ひとつの Rails アプリから 複数の Sidekiq プロセスを扱う

ひとつの Rails アプリで Sidekiq worker によって使う Redis を分けたい。

Sidekiq のプロセスはひとつの Redis と接続することを前提としているので、複数の Redis と接続する場合には Redis の数に合わせて Sidekiq のプロセスが必要になる。

ここではふたつの Sidekiq プロセスを扱い、接続先の Redis の URL は全て環境変数に入れるものとして書く。

config/initializers/sidekiq.rb

Sidekiq.configure_server do |config|
  config.redis = { url: ENV['REDIS_URL'] }
end

Sidekiq.configure_client do |config|
  config.redis = { url: ENV['REDIS_1_URL'] }
end

ざっくりと、 server は dequeue するほう (Sidekiq プロセス)、client は enqueue するほう (Rails アプリ) 。

client 側の設定は、とりあえずメインで接続するほうの Redis を設定しておけば良い。

Rails アプリの環境変数

  • REDIS_1_URL=redis://redis_1:6379
  • REDIS_2_URL=redis://redis_2:6379

Rails アプリ側では Redis の数だけ環境変数を用意する。

worker ひとつめ

ひとつめの worker はメインで接続するほうの Redis を使っているので普通に何も気にせず書いたら良い。

class Worker1
  include Sidekiq::Worker

  def perform(*args)
  end
end

Worker1.perform_async()

Sidekiq プロセスの環境変数

  • REDIS_URL=redis://redis_1:6379

worker ふたつめ

ふたつめの worker は、呼び出し側で接続先が違うことを書かないといけない。 詳しくはここにかいてある。 Sharding · mperham/sidekiq Wiki

class Worker2
  include Sidekiq::Worker

  def perform(*args)
  end
end

redis_2 = ConnectionPool.new { Redis.new(url: ENV['REDIS_2_URL']) }
Sidekiq::Client.via(redis_2) { Worker2.perform_async() }

Sidekiq プロセスの環境変数

  • REDIS_URL=redis://redis_2:6379

さいごに

ここまで書いたあとに worker にオプションとして渡す方法を知った。Conection Pool を都度生成するのはやめたいし、呼び出し側じゃなくて worker 側に書いてあるほうがわかりやすいのでこっちのほうが良さそうと思った。

class Worker2
  include Sidekiq::Worker
  sidekiq_options pool: ConnectionPool.new { Redis.new(url: ENV['REDIS_2_URL']) }
end

とはいえ、Sharding 自体はおすすめはされていなさそう。

Part of the reason I don't document sharding well is because it is supposed to be painful/last resort. It's better to start breaking your monolith into smaller services if you've reached the point of saturating a Redis instance. Questions about Sharding usage · Issue #3605 · mperham/sidekiq