Passing objects to a Sidekiq worker will not always work, and you should instead pass simple references to those objects.

Here is an example of what will not work:

class CalculateProgressWorker
  include Sidekiq::Worker

  def perform(user_id, date)
    Progress.calculate_for(user_id: user_id, date: date)
  end
end

The contrived example is a worker that calculates something (progress) based on information about user and date.

Progress.calculate_for expects user_id, and a Date object. Therefore, you might be inclined to do this when calling this worker:

today = Time.zone.today
CalculateProgressWorker.perform_async(user_id, today)

However, you will run into a type error if you pass in a Date object to the Sidekiq Worker.

Problem

Problem is that Sidekiq translates all your arguments into JSON format before storing them in the Redis queue. CalculateProgressWorker will then pull from the Redis queue and try to perform the task.

Sidekiq uses JSON.dump and JSON.load to store and pull data from Redis.

For example, you today object will be transformed as follows:

today = Time.zone.today
  => Sat, 23 May 2015
today.class
  => Date

# Sidekiq stores the data to Redis

today_in_redis = JSON.dump(today)
  => "\"2015-05-23\""
today_in_redis.class
  => String

# Sidekiq retrieves the data from Redis

retrieved_today = JSON.load(today_in_redis)
  => "2015-05-23"
retrieved_today.class
  => String

When the job is finally executed, your argument will have turned into a different type, thus causing unexpected behavior.

Solution

It is the best practice to keep your job parameters simple. Avoid passing complicated objects to Sidekiq workers.

In our example, we could explicitly pass String object to CalculateProgressWorker instead of Date object, and use Date.parse to parse the String back to Date.

class CalculateProgressWorker
  include Sidekiq::Worker

  def perform(user_id, date_string)
    Progress.calculate_for(user_id: user_id, date: Date.parse(date_string))
  end
end
today = Time.zone.today
CalculateProgressWorker.perform_async(user_id, today.to_s)

Calling #to_s on today is not entirely necessary because Sidekiq will transform today into String object as we saw before. However, it is a good idea to make it obvious to other readers that you are passing in String, not a Date.