Подтвердить что ты не робот

Как разрешить ошибку десериализации в отложенной работе?

Я пытаюсь использовать 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

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

Спасибо заранее!

4b9b3361

Ответ 1

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

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

Ответ 2

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

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

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

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

Ответ 3

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

Ответ 4

Там также зарегистрированная ошибка с 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

Ответ 5

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

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

Ответ 6

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

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

Возможными причинами могут быть:

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

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

Ответ 7

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

Попробуйте найти идентификатор задержки в журналах и играйте, чтобы разобрать его обработчик в 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'
  # ...
}