【问题标题】:delayed_job: how to force processing of failed jobsdelay_job:如何强制处理失败的作业
【发布时间】:2012-07-18 10:38:58
【问题描述】:

我正在维护一个 Rails 应用程序,我在该应用程序上运行延迟作业 gem 以发送电子邮件。

我刚刚注意到由于应用程序中的错误,过去几天我所有延迟的工作都失败了。现在错误已修复,我想尽快处理这些作业,但它们已经有太多失败的尝试,并且工作人员从数据库中拉出它们时有很大的延迟。

我已经尝试通过更新delayed_jobs 表并将尝试次数设置为较小的数字并将run_at 属性设置为当前时间,但仍然没有帮助。

你能告诉我如何强制工人执行它们吗?

【问题讨论】:

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


    【解决方案1】:

    你可以手动启动,试试

    Delayed::Job.all.each { |j| j.invoke_job }
    

    Delayed::Job.all.each { |j| j.payload_object.perform }
    

    【讨论】:

    • 听起来很合理,我现在就试试 :)
    • 所以,我已经尝试了这两种方法,但仍然没有处理作业。我是从 Rails 控制台做的,知道我做错了什么吗?
    【解决方案2】:

    现在错误已修复,我想尽快处理作业,但它们是 已经有太多失败的尝试,并且工人将它们从 数据库延迟很大。

    这意味着,由于作业并未从表中删除,因此仍有一些尝试用于延迟作业。延迟作业的默认行为是在找到可用作业时从队列中读取 5 个作业。没有太多代码更改的一种方法是在延迟配置中进行设置,该设置将从队列中获取更多作业并执行。你可以通过设置Delayed::Worker.read_ahead来配置它。

    # config/initializers/delayed_job_config.rb
    Delayed::Worker.destroy_failed_jobs = false
    Delayed::Worker.read_ahead = 10
    

    Delayed::Worker.destroy_failed_jobs 避免在最大尝试后删除作业,这也是一个可配置项。

    延迟作业每 5 秒检查一次数据库中的可用作业,它会在 5 + N ** 4 秒后尝试特定作业。所以,假设一个特定的工作已经失败了 24 次,那么轮到它在 331781 秒后到达,也就是说,如果我没记错的话,大约在 3 天之后。

    【讨论】:

    • 感谢您的建议。我已经完成了,但它并没有解决我的问题 - 我的目标是在下一次计划执行之前强制执行。
    【解决方案3】:

    好的,我终于明白了!

    诀窍实际上是将 run_at 属性更新为当前时间,但应用程序的当前时间 - 比数据库晚 3 小时。

    当我将其设置为 now() - 间隔“3 小时”时,所有作业都已处理完毕。

    编辑:

    @rodzyn,我已经尝试过你的建议,但仍然无法实现:

    [20] pry(main)> Delayed::Job.all.size
      Delayed::Backend::ActiveRecord::Job Load (0.6ms)  SELECT "delayed_jobs".* FROM "delayed_jobs" 
    => 1
    [21] pry(main)> Delayed::Job.first.invoke_job
      Delayed::Backend::ActiveRecord::Job Load (0.5ms)  SELECT "delayed_jobs".* FROM "delayed_jobs" LIMIT 1
      Order Load (0.4ms)  SELECT "orders".* FROM "orders" WHERE "orders"."id" = $1 LIMIT 1  [["id", "328"]]
      User Load (0.5ms)  SELECT "users".* FROM "users" WHERE "users"."id" = 1 LIMIT 1
    => nil
    [22] pry(main)> Delayed::Job.all.size
      Delayed::Backend::ActiveRecord::Job Load (0.6ms)  SELECT "delayed_jobs".* FROM "delayed_jobs" 
    => 1
    [23] pry(main)> 
    

    【讨论】:

    • 很难说这个答案实际上暗示了什么作为解决方案。对我来说,我只是在循环中更新以下内容,这将导致失败的作业在成功后被重新处理和删除: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 ,这个答案没有包含有关解决方案的足够信息。不过那是很久以前的事了,我不太记得当时的情况了。我已取消选中它,并且会在没有接受答案的情况下留下问题。
    【解决方案4】:

    现有答案中没有一个完全正确,所以我在这里添加。

    神奇的是让延迟的作业相信这些作业确实没有失败,所以通过 rails db 控制台:

    -> rails db
    development# update delayed_jobs set run_at = now() - interval '3 hours', attempts = 0, failed_at = null;
    UPDATE 30
    development# \q
    
    -> rake jobs:workoff  # a good one to use, because it will return immediately if no jobs are found
    

    “failed_at”或尝试字段都可以阻止作业运行。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-03-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-07-25
      • 1970-01-01
      • 1970-01-01
      • 2018-11-01
      相关资源
      最近更新 更多