如何解决Delayed Job中的反序列化错误?

35

我正在尝试使用DelayedJob,但作业失败,并在数据库中显示以下错误:

{Delayed::DeserializationError /Library/Ruby/Gems/1.8/gems/delayed_job-2.1.3/lib/delayed/serialization/active_record.rb:7:in `yaml_new' /System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/ruby/1.8/yaml.rb:133:in `transfer' /System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/ruby/1.8/yaml.rb:133:in `node_import' /System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/ruby/1.8/yaml.rb:133:in `load' /System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/ruby/1.8/yaml.rb:133:in `load' /Library/Ruby/Gems/1.8/gems/delayed_job-2.1.3/lib/delayed/backend/base.rb:79:in `payload_object' /Library/Ruby/Gems/1.8/gems/delayed_job-2.1.3/lib/delayed/backend/base.rb:87:in `invoke_job_without_newrelic_transaction_trace' (eval):3:in `invoke_job' /Library/Ruby/Gems/1.8/gems/newrelic_rpm-2.13.4/lib/new_relic/agent/instrumentation/controller_instrumentation.rb:252:in `perform_action_with_newrelic_trace' /Library/Ruby/Gems/1.8/gems/newrelic_rpm-2.13.4/lib/new_relic/agent/method_tracer.rb:141:in `trace_execution_scoped' /Library/Ruby/Gems/1.8/gems/newrelic_rpm-2.13.4/lib/new_relic/agent/instrumentation/controller_instrumentation.rb:247:in `perform_action_with_newrelic_trace' (eval):2:in `invoke_job' /Library/Ruby/Gems/1.8/gems/delayed_job-2.1.3/lib/delayed/worker.rb:120:in `run' /System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/ruby/1.8/timeout.rb:62:in `timeout' /Library/Ruby/Gems/1.8/gems/delayed_job-2.1.3/lib/delayed/worker.rb:120:in `run' /System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/ruby/1.8/benchmark.rb:308:in `realtime' /Library/Ruby/Gems/1.8/gems/delayed_job-2.1.3/lib/delayed/worker.rb:119:in `run' /Library/Ruby/Gems/1.8/gems/delayed_job-2.1.3/lib/delayed/worker.rb:177:in `reserve_and_run_one_job' /Library/Ruby/Gems/1.8/gems/delayed_job-2.1.3/lib/delayed/worker.rb:104:in `work_off' /Library/Ruby/Gems/1.8/gems/delayed_job-2.1.3/lib/delayed/worker.rb:103:in `times' /Library/Ruby/Gems/1.8/gems/delayed_job-2.1.3/lib/delayed/worker.rb:103:in `work_off' /Library/Ruby/Gems/1.8/gems/delayed_job-2.1.3/lib/delayed/worker.rb:78:in `start' /System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/ruby/1.8/benchmark.rb:308:in `realtime' /Library/Ruby/Gems/1.8/gems/delayed_job-2.1.3/lib/delayed/worker.rb:77:in `start' /Library/Ruby/Gems/1.8/gems/delayed_job-2.1.3/lib/delayed/worker.rb:74:in `loop' /Library/Ruby/Gems/1.8/gems/delayed_job-2.1.3/lib/delayed/worker.rb:74:in `start' /Library/Ruby/Gems/1.8/gems/delayed_job-2.1.3/lib/delayed/tasks.rb:9 /Library/Ruby/Gems/1.8/gems/rake-0.8.7/lib/rake.rb:636:in `call' /Library/Ruby/Gems/1.8/gems/rake-0.8.7/lib/rake.rb:636:in `execute' /Library/Ruby/Gems/1.8/gems/rake-0.8

不确定从哪里开始诊断这个问题。这之前从未发生过,我以前使用delayed job序列化模型对象没有任何问题。为什么这次会出现呢?

先行致谢!


我也遇到了这个问题。它似乎并不是每次都会发生,只是偶尔会出现。 - Tim Sullivan
你能否捕获错误并打印出它尝试反序列化的值?似乎YAML在某个地方卡住了你的数据。 - Dominic
2
也许可以检查一下数据库,看看失败的作业存储的值是什么? - Dominic
当作业失败时,DJ会删除记录。有没有办法关闭它? - Tim Sullivan
要防止 DJ 删除作业,请将“Delayed :: Worker.destroy_failed_jobs = false”添加到初始化文件中。 - Pan Thomakos
显示剩余3条评论
7个回答

69

这不是一个反序列化错误,而是在一个简单的 Model.find(id) 查询中出现了 ActiveRecord 记录未找到的错误。

如果您想了解详细信息,请在 rescue 语句中的 delayed_job-2.1.3/lib/delayed/serialization/active_record.rb 文件中记录它们,就在延迟作业愚蠢地引发 DeserializationError 并将有用的信息丢弃之前。


1
哇,谢谢你。有了这个错误,这是我最不怀疑的事情了。 - Joshua Pinter

12

Michiel是正确的。查看您的处理程序字段,例如“!ruby/ActiveRecord:YourClassName”的对象。

然后检查对象是否可以通过主键检索。

从控制台中,您还可以通过执行以下操作来测试此操作:

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

3

我认为这种情况发生在您对未保存或已删除的 AR 对象运行作业时,因为 AR 的反序列化通过 id 加载记录。如果您尝试延迟未保存的 AR 对象上的方法,则可能会引发异常。


是的,我卡了几个小时,通过将我的 before_save 回调函数调用我的 DJ 队列改为 after_save 回调函数进行修复。 - railsy

1

还有一个已记录的DJ错误,当传递到DB中处理程序字段的参数长度超过标准TEXT列时:

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

如果出现这种问题,将列更改为MEDIUMINT应该可以解决问题。
我在迁移中进行了如下操作:
change_column :delayed_jobs, :handler, :text, :limit => 16777215
ActiveRecord::Base.connection.execute("DELETE FROM delayed_jobs WHERE LENGTH(handler) >= 65535")

您可以通过简单的数据库查询来检查是否存在问题:
SELECT * FROM delayed_jobs WHERE LENGTH(handler) >= 65535

1

0

今天,我也遇到了这个错误,在进行繁琐的分析后发现:

  1. delayed_job将方法和参数转换为YAML格式并存储到数据库中
  2. 可以使用select * from delayed_jobs找到它;
  3. 当delayed_job无法反序列化时,会发生反序列化错误。

可能的原因可能是:

  1. 在调用延迟作业之前使用args [“xyz”],并在worker内部使用args [:xyz]
  2. 有时会将额外的参数传递给延迟作业对象,此时延迟作业无法构建对象,因为它是不确定的访问。

希望这能帮到你!


0
有时候当我们升级库时,延迟作业仍然保留旧的引用。
尝试在日志中查找延迟作业的ID,并解析其处理程序以查找错误引用。
j = DelayedJob.find(XXX)
data = YAML.load_dj(j.handler)
data.to_ruby

我提交了一个拉取请求来帮助解决这个问题。

同时,您可以使用这些代码行

# 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'
  # ...
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接