Как устранить ошибку десериализации в отложенной работе? - PullRequest
35 голосов
/ 17 февраля 2011

Я пытаюсь использовать 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.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 `each'
/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'
/Library/Ruby/Gems/1.8/gems/rake-0.8.7/bin/rake:31
/usr/bin/rake:19:in `load'
/usr/bin/rake:19

Не уверен, с чего начать диагностику этого.Этого раньше никогда не было, и я раньше использовал отложенную работу для сериализации объектов модели без каких-либо проблем.Почему на этот раз?

Заранее спасибо!

Ответы [ 7 ]

69 голосов
/ 28 февраля 2011

Это на самом деле не ошибка десериализации, это ошибка ActiveRecord, в которой запись не найдена в простом запросе Model.find (id).

Если вы хотите узнать подробности, запишите их в файл delayed_job-2.1.3/lib/delayed/serialization/active_record.rb в операторе спасения, незадолго до того, как отложенное задание тупо вызовет DeserializationError и выбросит полезную информацию.

12 голосов
/ 28 марта 2011

Мичиэль права.Посмотрите в поле вашего обработчика такие объекты, как "! Ruby / ActiveRecord: YourClassName"

Затем проверьте, можно ли получить объекты с помощью первичного ключа

С консоли вы также можете проверить это, выполнивчто-то вроде:

# first job in your delayed queue
YAML.load(Delayed::Backend::ActiveRecord::Job.first.handler)
3 голосов
/ 24 июня 2011

Я считаю, что это происходит, когда вы запускаете задание для несохраненного или удаленного объекта AR, поскольку десериализация для AR загружает запись по идентификатору.Вероятно, должно возникнуть исключение, если вы попытаетесь отложить метод для несохраненного объекта AR.

1 голос
/ 18 января 2014

Если кто-то хочет сделать delayed_job, просто завершите работу в режиме бездействия, вы можете сделать патч с этим кодом в инициализаторе:

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

1 голос
/ 20 декабря 2013

Есть также задокументированная ошибка с DJ, когда параметры, передаваемые в поле обработчика в БД, длиннее стандартного столбца 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
0 голосов
/ 07 июня 2019

Иногда, когда мы обновляем libs, отложенные задания по-прежнему сохраняют старые ссылки.

Попробуйте найти идентификатор delayed_job в журналах и воспроизвести, чтобы проанализировать его обработчик и ruby, чтобы найти неверную ссылку

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'
  # ...
}
0 голосов
/ 02 марта 2011

Сегодня я тоже страдал от этой ошибки и после суетного анализа нашел:

  1. delayed_job преобразует методы и параметры в формат YAML и сохраняет их в базе данных
  2. Его можно найти с помощью select * from delayed_jobs;
  3. ошибка десериализации возникает, когда delayed_job не может ее десериализовать.

Возможные причины:

  1. args ["xyz"] используется перед вызовом delayed_job и внутри работника, используя его как args [: xyz]
  2. Иногда дополнительные аргументы, передаваемые вместе с объектом в delayed_job, в то время, когда delayed_job не может создать объект, так как это равнодушный доступ.

Надеюсь, это поможет!

...