如何解决延迟作业中的反序列化错误?
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'
# ...
【讨论】:
以上是关于如何解决延迟作业中的反序列化错误?的主要内容,如果未能解决你的问题,请参考以下文章
如何在 .NET 中的反序列化期间指定 XML 序列化属性以支持命名空间前缀?