【问题标题】:Manually Retry Job in Delayed_job在 Delayed_job 中手动重试作业
【发布时间】:2011-03-19 17:31:23
【问题描述】:

Delayed::Job 的自动重试功能很棒,但我现在想手动重试一个作业。有没有一种方法我可以调用工作本身,比如......

Delayed::Job.all[0].perform

或者跑,或者别的什么。我尝试了一些东西,并梳理了文档,但无法弄清楚如何执行手动重试作业。

【问题讨论】:

  • Delayed::Worker.new.run(Delayed::Job.first) ref

标签: ruby-on-rails ruby rubygems delayed-job


【解决方案1】:

手动调用作业

Delayed::Job.find(10).invoke_job # 10 is the job.id

如果作业成功运行,这不会删除作业。您需要手动删除它:

Delayed::Job.find(10).destroy

【讨论】:

  • @joe 建议的替代方案更安全,尤其是当作业需要知道它是在脚本/控制台中还是在作业运行器中运行时。尝试将作业排队等待立即重试 Delayed::Job.first.update_attributes(:attempts=>0, :run_at=>Time.now, :failed_at => nil, :locked_by=>nil, :locked_at=>nil)
  • attempts 不能在 update_attributes 中分配,因为它是受保护的属性。我只是这样做:dj = Delayed::Job.first; dj.run_at = Time.now; dj.attempts = 0; dj.save!;
  • 集体完成这项工作(大约 100 个工作) Delayed::Job.where.all.each {|dj| dj.run_at = Time.now; dj.attempts = 0; dj.save!}
  • 我只是做Delayed::Job.where.not(last_error: nil).update_all(run_at: Time.current)
  • 如果作业失败,这不会设置 last_error 属性
【解决方案2】:
Delayed::Worker.new.run(Delayed::Job.last)

这将在完成后删除作业。

【讨论】:

  • 即使失败也会删除
  • 对于所有延迟的工作你可以做Delayed::Job.find_each(batch_size: 100) { |d| Delayed::Worker.new.run(d) }
  • @aledustet 当然不是。你乐观吗?
  • 这对我很有用,工作没有失败。没有尝试失败,但我真的怀疑它会删除它,这将是非常令人惊讶的。
【解决方案3】:

你完全可以按照你说的去做,找到工作并执行。

但是,我通常所做的只是将 run_at 设置回去,以便作业处理器重新拾取它。

【讨论】:

  • 延迟作业对象没有perform 方法。最接近的是Delayed::Job.find(10).payload_object.perform,不应该使用它。
【解决方案4】:

我在控制器中有一个用于测试目的的方法,当我点击一个 URL 时,它只会重置所有延迟的作业。不是超级优雅,但对我来说很好用:

# For testing purposes
  def reset_all_jobs
    Delayed::Job.all.each do |dj|
      dj.run_at = Time.now - 1.day
      dj.locked_at = nil
      dj.locked_by = nil
      dj.attempts = 0
      dj.last_error = nil
      dj.save
    end
    head :ok
  end

【讨论】:

  • 你不能使用 update_all ebcause 尝试是受保护的属性
  • update_all 直接使用 SQL,因此不调用验证(或受保护的属性等)
【解决方案5】:

上述先前的答案可能已过时。我发现我需要将 failed_at、locked_by 和 locked_at 设置为 nil:

(对于您要重试的每个作业):

d.last_error = nil
d.run_at = Time.now
d.failed_at = nil
d.locked_at = nil
d.locked_by = nil
d.attempts = 0
d.failed_at = nil # needed in Rails 5 / delayed_job (4.1.2)
d.save!

【讨论】:

    【解决方案6】:

    如果您需要重新运行的延迟作业失败,那么您只需选择它们并将所有涉及失败重试的内容设置为 null:

    Delayed::Job.where("last_error is not null").each do |dj|
      dj.run_at = Time.now.advance(seconds: 5)
      dj.locked_at = nil
      dj.locked_by = nil
      dj.attempts = 0
      dj.last_error = nil
      dj.failed_at = nil
      dj.save  
    end
    

    【讨论】:

      【解决方案7】:

      在开发环境中,通过rails console,按照 Joe Martinez 的建议,重试所有延迟作业的好方法是:

      Delayed::Job.all.each{|d| d.run_at = Time.now; d.save!}
      

      【讨论】:

      • 在 4.0.1 中更新 run_at 似乎还不够。我必须执行以下操作:Delayed::Job.where("failed_at is not null").each do |dj| dj.run_at = Time.now; dj.last_error = nil; dj.failed_at = nil; dj.save! end
      【解决方案8】:
      Delayed::Job.all.each(&:invoke_job)
      

      【讨论】:

        【解决方案9】:

        把它放在一个初始化文件中!

        module Delayed
          module Backend
            module ActiveRecord
              class Job
                def retry!
                  self.run_at = Time.now - 1.day
                  self.locked_at = nil
                  self.locked_by = nil
                  self.attempts = 0
                  self.last_error = nil
                  self.failed_at = nil
                  self.save!
                end
              end
            end
          end
        end
        

        然后你可以运行Delayed::Job.find(1234).retry!

        这基本上会将作业重新放入队列并正常处理。

        【讨论】:

        • 是的,这是一种将其放回待处理队列并让工作人员正常处理它的干净方法。我只建议不要使用Time.now - 1.day,而只使用Time.nowTime.zone.now。把它推迟一天是没有意义的(除了可能是为了优先考虑),如果以后再看它会增加混乱。
        猜你喜欢
        • 2013-01-14
        • 2011-10-14
        • 1970-01-01
        • 2021-05-28
        • 1970-01-01
        • 2019-10-25
        • 2011-01-16
        • 2019-10-09
        • 1970-01-01
        相关资源
        最近更新 更多