web-dev-qa-db-ja.com

遅延ジョブの逆シリアル化エラーを解決するにはどうすればよいですか?

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。フレームワーク/バージョン/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/delayd_job-2.1.3/lib/delayd/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/delayd/worker.rb:119:in `run '
/Library/Ruby/Gems/1.8/gems/delayed_job-2.1.3/lib/delayd/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_o ff '
/Library/Ruby/Gems/1.8/gems/delayed_job-2.1.3/lib/delayed/worker.rb:103:in`times' 
/Library/Ruby/Gems/1.8/gems/delayd_job-2.1.3/lib/delayd/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/delayd_job-2.1.3/lib/delayd/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/rak e.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' 
/Library/Ruby/Gems/1.8/gems/rake-0.8.7/bin/rake:31 
/usr/bin/rake:19:in `load '
/usr/bin/rake:19 

これを診断するためにどこから始めればよいかわからない。これはこれまでに発生したことはなく、以前は遅延ジョブを使用してモデルオブジェクトを問題なくシリアル化しました。今回はなぜですか?

前もって感謝します!

35
deruse

これは実際には逆シリアル化エラーではなく、単純なModel.find(id)クエリでのActiveRecordレコードが見つかりませんエラーです。

詳細を知りたい場合は、遅延ジョブが愚かにDeserializationErrorを上げて有用な情報を破棄する直前に、rescueステートメントのdelayed_job-2.1.3/lib/delayed/serialization/active_record.rbファイルに記録してください。

69
Michiel de Mare

ミシエルは正しい。 「!Ruby/ActiveRecord:YourClassName」のようなオブジェクトのハンドラーフィールドを見てください

次に、主キーを介してオブジェクトを取得できるかどうかを確認します

コンソールから、次のようにしてこれをテストすることもできます。

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

これは、ARの逆シリアル化によってレコードがIDで読み込まれるため、保存されていない、または削除されたARオブジェクトに対してジョブを実行したときに発生すると思います。保存されていないARオブジェクトのメソッドを遅らせようとすると、おそらく例外がスローされます。

3
Harshal_m_joshi

誰かがdelayed_jobをno-opとしてジョブを終了させたい場合は、初期化子でこのコードを使用してモンキーパッチを適用できます。

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

1
spilliton

DBのハンドラフィールドに渡されるパラメータが標準の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")

単純なDBクエリの問題かどうかを確認できます。

SELECT * FROM delayed_jobs WHERE LENGTH(handler) >= 65535
1
ideaoforder

今日、私もこのエラーに苦しみ、多忙な分析を行った後、次のことがわかりました。

  1. delayd_jobはメソッドとパラメーターをYAML形式に変換し、データベースに保存します
  2. select * from delayed_jobsを使用して見つけることができます。
  3. 逆シリアル化エラーは、delayed_jobが逆シリアル化できない場合に発生します。

考えられる原因は次のとおりです。

  1. args ["xyz"]は、delayed_jobを呼び出す前に使用され、内部ワーカーはそれをargs [:xyz]として使用します。
  2. 時々、delayed_jobが無関心なアクセスであるため、delayed_jobがオブジェクトの構築に失敗するときに、オブジェクトとともにdelayed_jobに追加の引数が渡されます。

これがお役に立てば幸いです。

0
Sandip Ransing

Libsをアップグレードしても、遅延したジョブは古い参照を保持することがあります。

ログでdelayed_jobのIDを見つけて、そのハンドラーを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
Raúl Cabrera