Tam
Tam

Reputation: 12042

Weird exception with delayed_job

Trying to queue a job with delayed_job as follows:

Delayed::Job.enqueue(BackgroundProcess.new(current_user, object))

current_user and object are not nil when I print them out. The weird thing is that sometimes refreshing the page or running the command again works!

Here is the exception trace:

  Delayed::Backend::ActiveRecord::Job Columns (44.8ms)   SHOW FIELDS FROM `delayed_jobs`

TypeError (wrong argument type nil (expected Data)):
  /Users/.rvm/rubies/ruby-1.9.1-p378/lib/ruby/1.9.1/yaml.rb:391:in `emit'
  /Users/.rvm/rubies/ruby-1.9.1-p378/lib/ruby/1.9.1/yaml.rb:391:in `quick_emit'
  /Users/.rvm/rubies/ruby-1.9.1-p378/lib/ruby/1.9.1/yaml/rubytypes.rb:86:in `to_yaml'
  vendor/plugins/delayed_job/lib/delayed/backend/base.rb:65:in `payload_object='
  activerecord (2.3.9) lib/active_record/base.rb:2918:in `block in assign_attributes'
  activerecord (2.3.9) lib/active_record/base.rb:2914:in `each'
  activerecord (2.3.9) lib/active_record/base.rb:2914:in `assign_attributes'
  activerecord (2.3.9) lib/active_record/base.rb:2787:in `attributes='
  activerecord (2.3.9) lib/active_record/base.rb:2477:in `initialize'
  activerecord (2.3.9) lib/active_record/base.rb:725:in `new'
  activerecord (2.3.9) lib/active_record/base.rb:725:in `create'
  vendor/plugins/delayed_job/lib/delayed/backend/base.rb:21:in `enqueue'

Upvotes: 5

Views: 1621

Answers (2)

Brian Armstrong
Brian Armstrong

Reputation: 19901

Ran into this same problem as well. I still don't know what is causing it, but for some reason cloning the object seems to solve it

u = User.find 123
u.to_yaml
=> TypeError: wrong argument type nil (expected Data)
u.clone.to_yaml
=> works like normal

Very frustrating. Would be better to know the root cause, but this might help if you are desperate.

Upvotes: 0

DanneManne
DanneManne

Reputation: 21180

I would guess that it is caused by the fact that you send the objects as arguments to your jobs (at least I assume that current_user and object are in fact objects and not id's). Send the id's instead and start with loading the objects when perform starts.

For example:

Delayed::Job.enqueue(BackgroundProcess.new(current_user.id, object.id))

class BackgroundProcess < Struct.new(:user_id, :object_id)
  def perform
    @current_user = User.find(user_id)
    @object = Object.find(object_id)

    ...
  end
end

This way, it does not risk any problem with serializing an ActiveRecord into the database and you will always load the latest changes when the job is run.

Upvotes: 7

Related Questions