Sidekiq's best practice, if you're using ActiveJob, that's not the case

The official Sidekiq Best Practices Says that the perform method should pass the id of the object instead of the object, but that's not the case if you're using 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.

Complex Ruby objects cannot be converted to JSON. By default it will be converted using to_s and the result will be something like # <Quote: 0x0000000006e57288>.

What if the value of the quote object changes while it is being queued, even if it can be serialized? Instead of saving the state in Sidekiq, save the simple ID. Then, make sure to find the object when you actually need it in the perform method.

However, according to the ActiveJob Style Guide, passing the id is bad, so I will introduce it.

# 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

When passing Active Record Model as an argument, it is automatically serialized and deserialized using a mechanism called GlobalID, so there is no need to manually deserialize.

Also, having GlobalID seems to be able to handle model property mismatches properly.

If you don't have this mechanism, it's best to follow Sidekiq best practices.

Recommended Posts

Sidekiq's best practice, if you're using ActiveJob, that's not the case
Write a null case using the Optional type without using an if statement
If rbenv install is not successful, try using the environment variable "RUBY_BUILD_CURL_OPTS".