手动重试Delayed_job中的作业

79

Delayed::Job的自动重试功能很好,但我现在想手动重试一个作业。有没有一个我可以在作业本身上调用的方法,就像...

Delayed::Job.all[0].perform

我尝试了一些方法,并查阅了文档,但是无法找到如何手动重试作业的执行方式。


4
Delayed::Worker.new.run(Delayed::Job.first) - Jake Berger
9个回答

116
手动调用一个任务
Delayed::Job.find(10).invoke_job # 10 is the job.id

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

Delayed::Job.find(10).destroy

10
@joe提出的替代方案更加安全可靠,特别是当工作需要知道它是在脚本/控制台中运行还是在作业运行程序中运行时。尝试使用以下代码立即将作业排队以进行重试:Delayed::Job.first.update_attributes(:attempts=>0, :run_at=>Time.now, :failed_at => nil, :locked_by=>nil, :locked_at=>nil) - so_mv
8
由于attempts是受保护的属性,因此无法在update_attributes中进行赋值。我只需执行以下操作:dj = Delayed::Job.first; dj.run_at = Time.now; dj.attempts = 0; dj.save!; - Anjan
批量处理这个问题的方法是有效的(大约100个任务)。Delayed::Job.where.all.each {|dj| dj.run_at = Time.now; dj.attempts = 0; dj.save!} - tobinharris
1
我只是执行 Delayed::Job.where.not(last_error: nil).update_all(run_at: Time.current) - Jason Galuten
如果作业失败,这不会设置last_error属性。 - localhostdotdev

40
Delayed::Worker.new.run(Delayed::Job.last)

完成后将删除该作业。


即使失败,它也会将其删除。 - aledustet
1
对于所有延迟作业,您可以执行 Delayed::Job.find_each(batch_size: 100) { |d| Delayed::Worker.new.run(d) } - MatayoshiMariano
1
@aledustet 当然不是。你确定吗? - Joshua Pinter
这对我有用,对于一个没有失败的工作。没有尝试过失败的工作,但我真的怀疑它会删除它,那将是非常令人惊讶的。 - dzajic

12

您可以按照您所说的方式执行,找到该作业并运行 perform。

然而,通常我所做的是将 run_at 设置回来,以便作业处理器再次获取它。


1
延迟工作对象中没有“perform”方法。最接近的是Delayed :: Job.find(10).payload_object.perform,但不应使用该方法。 - lulalala

10

我在控制器中有一个用于测试的方法,当我访问某个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

1
你不能使用update_all,因为尝试更新受保护的属性。 - Ivailo Bardarov
3
update_all 直接使用 SQL,因此不会触发验证(或受保护的属性等)。 - Michael

8
之前的答案可能已过时。我发现我需要将 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!

5

如果您有需要重新运行的失败延迟作业,那么您只需要选择它们并将所有与失败重试相关的设置都设置为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

4
在开发环境中,通过rails console,遵循Joe Martinez的建议,重试所有延迟的作业的好方法是:
Delayed::Job.all.each{|d| d.run_at = Time.now; d.save!}

6
在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 - steakchaser

3
Delayed::Job.all.each(&:invoke_job)

2

请将以下内容放入初始化文件中!

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!

这将把作业重新放回队列并正常处理它。


1
是的,这是一种干净的方式将其放回队列中进行处理,并让工作人员正常处理它。我建议不要使用 Time.now - 1.day,而是直接使用 Time.nowTime.zone.now。没有必要将其推迟一天(除非是为了优先级),如果以后查看此代码可能会增加混淆。 - Joshua Pinter

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接