Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How does Sidekiq passes arguments to the perform method?

Tags:

ruby

sidekiq

I have this Sidekiq worker:

class DealNoteWorker
  include Sidekiq::Worker
  sidekiq_options queue: :email

  def perform(options = {})
    if options[:type] == "deal_watch_mailer"
      deal_watchers = DealWatcher.where("deal_id = ?", options[:deal_id])

      deal_note = DealNote.find(options[:deal_note_id])

      current_user = User.find(options[:current_user_id])

      deal_watchers.each do |deal_watcher|
        unless deal_watcher.user_id == options[:current_user_id]
          # Tell the DealWatchMailer to send emails to ALL watchers advising of change to deal
          if deal_watcher.user.active
            DealWatchMailer.deal_watch_email(deal_watcher, nil, deal_note, current_user, options[:url]).deliver
          end
        end
      end
    elsif options[:type] == "deal_note_mailer"
      options[:user_ids].each do |id|
        if DealWatcher.where("deal_id = ? and user_id =?", options[:deal_id], id).count == 0
          deal_note = Deal.find(options[:deal_note_id])
          user = User.find_by_id(id)
          DealNoteMailer.deal_note_email(deal_note, user, options[:url]).deliver
        end
      end
    end
  end
end

I pass a hash to the perform_async method, but I think that the parameters transfered to the perform method are not of the same type as the ones passed to perform_async. I tried to user logger.info and p to debug my issue but nothing gets outputted...

The issue is that the job is added to the email queue but never gets processed. I even tried to raise an exception in the perform method (on the first line of the method) but nothing was outputted either...

I know as a fact that the following worker works:

class DealNoteWorker
  include Sidekiq::Worker

  def perform(deal_id, deal_note_id, current_user_id, url)
    deal_watchers = DealWatcher.where("deal_id = ?", deal_id)

    deal_note = DealNote.find(deal_note_id)

    current_user = User.find(current_user_id)

    deal_watchers.each do |deal_watcher|
      unless deal_watcher.user_id == current_user_id
        # Tell the DealWatchMailer to send emails to ALL watchers advising of change to deal
        if deal_watcher.user.active
          DealWatchMailer.deal_watch_email(deal_watcher, nil, deal_note, current_user, url).deliver
        end
      end
    end
  end
end

So the problem lies in the hash parameter (options). What am I doing wrong please?

like image 717
Peter Butterworth Avatar asked Apr 03 '13 15:04

Peter Butterworth


People also ask

How does Sidekiq work in Rails?

Sidekiq server process pulls jobs from the queue in Redis and processes them. Like your web processes, Sidekiq boots Rails so your jobs and workers have the full Rails API, including Active Record, available for use. The server will instantiate the worker and call perform with the given arguments.

What is Sidekiq process?

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.

How do Sidekiq queues work?

It works the same way as the scheduled queue; it contains jobs that have to be executed at a given time in the future. The main difference is that in retries queue, jobs are added by the Sidekiq, and the time when the job should be executed is calculated based on the retries counter.

What does Sidekiq store in Redis?

Sidekiq is usually the background job processor of choice for Ruby-on-Rails, and uses Redis as a data store for the job queues.


1 Answers

From the Sidekiq documentation:

The arguments you pass to perform_async must be composed of simple JSON datatypes: string, integer, float, boolean, null, array and hash. The Sidekiq client API uses JSON.dump to send the data to Redis. The Sidekiq server pulls that JSON data from Redis and uses JSON.load to convert the data back into Ruby types to pass to your perform method. Don't pass symbols or complex Ruby objects (like Date or Time!) as those will not survive the dump/load round trip correctly.

You can see this on the console:

> options = { :a => 'b' }
> how_sidekiq_stores_the_options = JSON.dump(options)
> how_sidekiq_loads_the_options = JSON.load(how_sidekiq_stores_the_options)
> how_sidekiq_stores_the_options == how_sidekiq_loads_the_options
  false

It looks like you are using symbols as the keys for your options hash. If you switch to string keys, it should work.

like image 96
mertonium Avatar answered Sep 19 '22 20:09

mertonium