公式があげている Sidekiq のベストプラクティスによると、perform メソッドにはオブジェクトではなくオブジェクトの id を渡すようにと書かれていますが、Rails の ActiveJob を使っている場合はその限りではないという話です。
MISTAKE
quote = Quote.find(quote_id)
SomeWorker.perform_async(quote)
Complex Ruby objects do not convert to JSON, by default it will convert with to_s and look like #Quote:0x0000000006e57288. Even if they did serialize correctly, what happens if your queue backs up and that quote object changes in the meantime? Don't save state to Sidekiq, save simple identifiers. Look up the objects once you actually need them in your perform method.
複雑なRubyオブジェクトはJSONに変換することができません。デフォルトでは to_s を使って変換することになり、その結果は #Quote:0x0000000006e57288 のようになります。
たとえシリアライズができたとしても、キューに保存されている間に quoteオブジェクトの値が変更されたらどうでしょうか? 状態をSidekiqに保存するのではなく、シンプルなIDを保存してください。 そして、performメソッド内で実際に必要になったタイミングで、オブジェクトを find するようにしてください。
しかし、ActiveJob Style Guide によると id を渡すのは bad と書かれていたので紹介します。
# bad - passing by id
# Deserialization error is reported, the job *is* scheduled for retry.
class SomeJob < ApplicationJob
def perform(model_id)
model = Model.find(model_id)
do_something_with(model)
end
end
# bad - model mismatch
class SomeJob < ApplicationJob
def perform(model_id)
Model.find(model_id)
# ...
end
end
# Will try to fetch a Model using another model class, e.g. User's id.
SomeJob.perform_later(user.id)
# acceptable - passing by id
# Deserialization error is reported, the job is *not* scheduled for retry.
class SomeJob < ApplicationJob
def perform(model_id)
model = Model.find(model_id)
do_something_with(model)
rescue ActiveRecord::RecordNotFound
Rollbar.warning('Not found')
end
end
# good - passing with GlobalID
# Deserialization error is reported, the job is *not* scheduled for retry.
class SomeJob < ApplicationJob
def perform(model)
do_something_with(model)
end
end
Active Record Model を引数で渡す場合、GlobalID という仕組みを用いて自動でシリアライズ、デシリアライズするため、手動でデシリアイズする必要がないとのこと。
また、GlobalID があることで、モデルのプロパティのミスマッチを適切に処理することができるそうです。
このような仕組みがない場合は、Sidekiq のベストプラクティスに則った方が良いでしょう。