How to resolve deserialization error in delayed job?

你。 提交于 2019-12-03 04:15:54
|improve this question

It's not really a deserialization error, it's an ActiveRecord record-not-found error on a simple Model.find(id) query.

If you want to know the details, log them in the delayed_job-2.1.3/lib/delayed/serialization/active_record.rb file, in the rescue statement, just before delayed-job stupidly raises the DeserializationError and throws the useful information away.

Michiel is right. Look at your handler field for objects like "!ruby/ActiveRecord:YourClassName"

Then check if objects can be retrieved via the primary key

From the console you can also test this out by doing something like:

# first job in your delayed queue
YAML.load(Delayed::Backend::ActiveRecord::Job.first.handler)

I believe this occurs when you run a job against an unsaved or deleted AR object since the deserialization for AR loads the record by id. An exception should probably be thrown if you attempt to delay a method on an unsaved AR object.

There's also a documented bug with DJ when the params passed into the handler field in the DB are longer than a standard TEXT column:

https://github.com/collectiveidea/delayed_job/issues/491

If this happens to be your problem, changing the column to a MEDIUMINT should fix the issue.

I did this in a migration like so:

change_column :delayed_jobs, :handler, :text, :limit => 16777215
ActiveRecord::Base.connection.execute("DELETE FROM delayed_jobs WHERE LENGTH(handler) >= 65535")

You can check to see if it's an issue with a simple DB query:

SELECT * FROM delayed_jobs WHERE LENGTH(handler) >= 65535

If anyone wants to make delayed_job just finish the job as a no-op you can monkey patch with this code in the initializer:

https://gist.github.com/spilliton/8494752

Sandip Ransing

Today, I also suffered through this error and after doing hectic analysis found:

  1. delayed_job converts methods & parameters to YAML format and stores it into database
  2. It can be found using select * from delayed_jobs;
  3. deserialization error occurs when delayed_job is not able to deserialize it.

Probable causes can be:

  1. args["xyz"] used before calling delayed_job & inside worker using it as args[:xyz]
  2. Sometimes extra arguments passed along with object to delayed_job that time delayed_job fails to build object as it is indifferent access.

I Hope this will help!

Sometimes when we upgrade libs delayed jobs still keep old references.

Try to find the id of delayed_job in logs and play to parse its handler to ruby to find the wrong reference

j = DelayedJob.find(XXX)
data = YAML.load_dj(j.handler)
data.to_ruby

I made a pull request to help with this problem.

Meanwhile you can use this lines

# config/initializers/delayed_job.rb

# Monkey patch to use old class references
module Psych

  class << self; attr_accessor :old_class_references end
  @old_class_references = {}

  class ClassLoader
    private

    def find klassname
      klassname = ::Psych.old_class_references[klassname] || klassname
      @cache[klassname] ||= resolve(klassname)
    end
  end

  module Visitors
    class ToRuby < Psych::Visitors::Visitor
      def revive klass, node
        if klass.is_a? String
          klassname = ::Psych.old_class_references[klass] || klass
          klass = Kernel.const_get(klassname) rescue klassname
        end
        s = register(node, klass.allocate)
        init_with(s, revive_hash({}, node), node)
      end
    end
  end
end

# Add all old dependencies (hash keys) pointing to new references (hash values)
Psych.old_class_references = {
  'ActiveRecord::AttributeSet' => 'ActiveModel::AttributeSet'
  # ...
}
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!