How to resolve deserialization error in delayed job?

前端 未结 7 1962
遇见更好的自我
遇见更好的自我 2021-02-06 22:38

I am trying to use DelayedJob and the job is failing, giving the following error in the database:

{Delayed::DeserializationError
/Library/Ruby/Gems/1.8/gems/delayed_j         


        
相关标签:
7条回答
  • 2021-02-06 23:01

    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.

    0 讨论(0)
  • 2021-02-06 23:01

    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)
    
    0 讨论(0)
  • 2021-02-06 23:09

    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'
      # ...
    }
    
    0 讨论(0)
  • 2021-02-06 23:14

    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

    0 讨论(0)
  • 2021-02-06 23:18

    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!

    0 讨论(0)
  • 2021-02-06 23:20

    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.

    0 讨论(0)
提交回复
热议问题