【问题标题】:Retry Sidekiq worker from within worker从工作人员内部重试 Sidekiq 工作人员
【发布时间】:2018-11-05 14:51:10
【问题描述】:

在我的应用程序中,我尝试按顺序执行两个工作任务。 首先,使用 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-rails ruby-on-rails-5 sidekiq


    【解决方案1】:

    如果您不想拥有嵌套的工作人员,那么在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
    

    【讨论】:

    • 谢谢,我想我会选择这个选项
    • 重试次数为 7 大约需要 2500 秒,而 8 大约需要 4000 秒。我会坚持7,应该是完美的。
    【解决方案2】:

    我相信“正确”和最异步的方法是有两个队列和两个工人:

    • 队列 1:创建 PdfWorker
    • 队列 2:SendPdfWorker

    当 CreatePdfWorker 生成 PDF 后,它会将 SendPdfWorker 与新生成的 PDF 和收件人一起排队。

    这样,每个工作人员都可以独立工作并异步从队列中提取,而您不必为 Sidekiq 的设计选择而苦恼。

    【讨论】:

    • 是的,绝对是最好的选择。但是我失去了对我不喜欢的控制器操作的可见性。此外,在创建 PDF 时触发电子邮件也是违反直觉的。我希望我的员工像微服务一样工作并且是自主的。我找到了一个猴子补丁:向上述工作人员添加第三个参数,迭代直到达到某个值......虽然不是很好......
    猜你喜欢
    • 2013-07-10
    • 2013-11-05
    • 1970-01-01
    • 2013-09-16
    • 2015-03-10
    • 2012-10-05
    • 1970-01-01
    • 2013-03-10
    • 1970-01-01
    相关资源
    最近更新 更多