首页 > 解决方案 > 从工作人员内部重试 Sidekiq 工作人员

问题描述

在我的应用程序中,我试图按顺序执行两个工作任务。首先,使用 Wicked pdf 创建 PDF,然后在创建 PDF 后,向两个不同的收件人发送附有 PDF 的电子邮件。

这就是控制器中的调用:

PdfWorker.perform_async(@d.id)
MailingWorker.perform_in(1.minutes, @d.id,@d.class.name.to_s)

第一个工作人员创建 PDF,第二个工作人员发送电子邮件。

这是第二个工人:

class MailingWorker
  include Sidekiq::Worker
  sidekiq_options retry: false    
  def perform(d_id,model)

    @d = eval(model).find(d_id)
    @model = model
    if @d.pdf.present?
      ProfessionnelMailer.notification_d(@d).deliver
      ClientMailer.notification_d(@d).deliver
    else
      MailingWorker.perform_in(1.minutes, @d.id, @model.to_s)
    end
  end
end

if 语句检查是否已创建 PDF。如果真的发送了两封邮件,否则一分钟后再次调用同一个工作人员,只是为了让 Heroku 服务器有额外的时间来处理 PDF 创建,以防需要更多时间或排长队。

尽管如果 PDF 确实无法处理,则上述内容会陷入无限循环。

有没有办法来解决这个问题 ?

我看到的一个选项是在 PDF 创建工作人员中调用第二个工作人员,尽管我真的不想将工作人员嵌套得太深。将它们分开使我的控制器更加清晰,我可以看到操作的顺序。但欢迎任何建议。

另一种选择是使用sidekiq_options retry: 5并请求重试控制器,该重试可计入全部 5 次重试,而不是重试工作人员,else MailingWorker.perform_in(1.minutes, @d.id, @model.to_s)但我不知道该怎么做。根据此线程https://github.com/mperham/sidekiq/issues/769将引发异常,但我不确定如何执行此操作...(我也不确定重试将等待多长时间在使用异常方法处理之前,通过上面的解决方案我可以控制时间范围..)

标签: ruby-on-railsruby-on-rails-5sidekiq

解决方案


如果您不想拥有嵌套的工作人员,那么MailingWorker如果 PDF 不存在,则不要再次将其排队,而是引发异常。此外,配置工作重试选项,以便 sidekiq 将其推送到重试队列并在某个时间再次运行它。根据文件,

Sidekiq will retry failures with an exponential backoff using the 
formula (retry_count ** 4) + 15 + (rand(30) * (retry_count + 1)) (i.e. 
15, 16, 31, 96, 271, ... seconds + a random amount of time). It will 
perform 25 retries over approximately 21 days.

工人代码会更像,

class MailingWorker
  include Sidekiq::Worker
  sidekiq_options retry: 5

  def perform(d_id,model)

    @d = eval(model).find(d_id)
    @model = model
    if @d.pdf.present?
      ProfessionnelMailer.notification_d(@d).deliver
      ClientMailer.notification_d(@d).deliver
    else
      raise "PDF not present"
    end
  end
end

推荐阅读