如何解决延迟作业中的反序列化错误?

Posted

技术标签:

【中文标题】如何解决延迟作业中的反序列化错误?【英文标题】:How to resolve deserialization error in delayed job? 【发布时间】:2011-06-28 17:41:26 【问题描述】:

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

延迟::反序列化错误 /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.7/lib/rake.rb:631:in `each' /Library/Ruby/Gems/1.8/gems/rake-0.8.7/lib/rake.rb:631:in `execute' /Library/Ruby/Gems/1.8/gems/rake-0.8.7/lib/rake.rb:597:in `invoke_with_call_chain' /System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/ruby/1.8/monitor.rb:242:in `synchronize' /Library/Ruby/Gems/1.8/gems/rake-0.8.7/lib/rake.rb:590:in `invoke_with_call_chain' /Library/Ruby/Gems/1.8/gems/rake-0.8.7/lib/rake.rb:583:in `invoke' /Library/Ruby/Gems/1.8/gems/rake-0.8.7/lib/rake.rb:2051:in `invoke_task' /Library/Ruby/Gems/1.8/gems/rake-0.8.7/lib/rake.rb:2029:in `top_level' /Library/Ruby/Gems/1.8/gems/rake-0.8.7/lib/rake.rb:2029:in `每个' /Library/Ruby/Gems/1.8/gems/rake-0.8.7/lib/rake.rb:2029:in `top_level' /Library/Ruby/Gems/1.8/gems/rake-0.8.7/lib/rake.rb:2068:in `standard_exception_handling' /Library/Ruby/Gems/1.8/gems/rake-0.8.7/lib/rake.rb:2023:in `top_level' /Library/Ruby/Gems/1.8/gems/rake-0.8.7/lib/rake.rb:2001:in `run' /Library/Ruby/Gems/1.8/gems/rake-0.8.7/lib/rake.rb:2068:in `standard_exception_handling' /Library/Ruby/Gems/1.8/gems/rake-0.8.7/lib/rake.rb:1998:in `run' /图书馆/Ruby/Gems/1.8/gems/rake-0.8.7/bin/rake:31 /usr/bin/rake:19:in `load' /usr/bin/rake:19

不知道从哪里开始诊断。这以前从未发生过,我之前使用延迟作业来序列化模型对象而没有任何问题。为什么这次?

提前致谢!

【问题讨论】:

我也遇到过这个问题。它似乎不是每次都会发生,只是有时会发生。 你能捕捉到错误并打印出它试图反序列化的值吗? YAML 似乎在某处阻塞了您的数据。 我不确定在哪里发现错误,因为这似乎发生在 DJ 的代码中。 也许检查您的数据库并查看失败作业的存储值是什么? 作业失败时,DJ 删除记录。有没有办法关闭它? 【参考方案1】:

这并不是真正的反序列化错误,它是一个简单的 Model.find(id) 查询中的 ActiveRecord 记录未找到错误。

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

【讨论】:

哇,谢谢你。有了这个错误,这是我怀疑的最后一件事。【参考方案2】:

米歇尔是对的。查看处理程序字段中的对象,例如“!ruby/ActiveRecord:YourClassName”

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

您还可以在控制台中通过以下方式进行测试:

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

【讨论】:

【参考方案3】:

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

【讨论】:

是的,我被困了几个小时,并通过将调用我的 DJ 队列的 before_save 回调设置为 after_save 回调来修复它【参考方案4】:

当传递到数据库中的处理程序字段的参数比标准的 TEXT 列长时,DJ 还存在一个已记录的错误:

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

【讨论】:

【参考方案5】:

如果有人想让delayed_job 以无操作的方式完成工作,您可以在初始化程序中使用以下代码进行猴子补丁:

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

【讨论】:

【参考方案6】:

今天,我也遇到了这个错误,经过忙碌的分析发现:

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

可能的原因可能是:

    args["xyz"] 在调用delayed_job 之前使用& 内部worker 使用它作为args[:xyz] 有时额外的参数与对象一起传递给delayed_job,此时delayed_job 无法构建对象,因为它是无关紧要的访问。

我希望这会有所帮助!

【讨论】:

【参考方案7】:

有时当我们升级库时,延迟的作业仍然保留旧的引用。

尝试在日志中找到delayed_job的id并播放解析其处理程序到ruby以找到错误的引用

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

我发了pull request 来帮助解决这个问题。

同时你可以使用这条线

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

【讨论】:

以上是关于如何解决延迟作业中的反序列化错误?的主要内容,如果未能解决你的问题,请参考以下文章

使用延迟作业发送电子邮件时报告错误

BurpWeb安全学院[不安全的反序列化]

如何在 .NET 中的反序列化期间指定 XML 序列化属性以支持命名空间前缀?

如何在 Elastic Beanstalk 上设置延迟作业时修复“需要”错误

如何去掉Json字符串中反斜杠

XML 文档中的反序列化错误(1,1)