从工作人员内部重试 Sidekiq 工作人员
Retry Sidekiq worker from within worker
在我的应用程序中,我试图按顺序执行两个辅助任务。
首先,使用 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 是否已创建。如果 true 发送两封邮件,否则,一分钟后再次调用同一个工作人员,只是为了让 Heroku 服务器有额外的时间来处理 PDF 创建,以防需要更多时间或排长队。
虽然如果 PDF 确实处理失败,但上面的代码会陷入无限循环。
有办法解决这个问题吗?
我看到的一个选项是调用 PDF 创建工作器中的第二个工作器,但我真的不想将工作器嵌套得太深。将它们分开使我的控制器更加清晰,我可以看到操作顺序。但欢迎任何建议。
另一种选择是使用 sidekiq_options retry: 5
并请求重试控制器,这可以计入总共 5 次重试,而不是使用 else MailingWorker.perform_in(1.minutes, @d.id, @model.to_s)
重试 worker 但我没有知道怎么做。根据这个线程https://github.com/mperham/sidekiq/issues/769,它会引发异常,但我不知道该怎么做......(我也不确定在用异常方法处理之前重试将等待多长时间,与上面的解决方案我可以控制时间范围..)
我相信 "correct" 和最异步的方法是有两个队列和两个工作人员:
- 队列 1:CreatePdfWorker
- 队列 2:SendPdfWorker
当 CreatePdfWorker 生成 PDF 后,它会将新生成的 PDF 和收件人加入 SendPdfWorker 队列。
这样,每个 worker 都可以独立工作并异步地从队列中取出,并且您不会与 Sidekiq 的设计选择作斗争。
如果您不想拥有嵌套的 worker,那么在 MailingWorker
中而不是再次排队,如果 PDF 不存在则引发异常。
此外,配置 worker 重试选项,这样 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
在我的应用程序中,我试图按顺序执行两个辅助任务。 首先,使用 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 是否已创建。如果 true 发送两封邮件,否则,一分钟后再次调用同一个工作人员,只是为了让 Heroku 服务器有额外的时间来处理 PDF 创建,以防需要更多时间或排长队。
虽然如果 PDF 确实处理失败,但上面的代码会陷入无限循环。
有办法解决这个问题吗?
我看到的一个选项是调用 PDF 创建工作器中的第二个工作器,但我真的不想将工作器嵌套得太深。将它们分开使我的控制器更加清晰,我可以看到操作顺序。但欢迎任何建议。
另一种选择是使用 sidekiq_options retry: 5
并请求重试控制器,这可以计入总共 5 次重试,而不是使用 else MailingWorker.perform_in(1.minutes, @d.id, @model.to_s)
重试 worker 但我没有知道怎么做。根据这个线程https://github.com/mperham/sidekiq/issues/769,它会引发异常,但我不知道该怎么做......(我也不确定在用异常方法处理之前重试将等待多长时间,与上面的解决方案我可以控制时间范围..)
我相信 "correct" 和最异步的方法是有两个队列和两个工作人员:
- 队列 1:CreatePdfWorker
- 队列 2:SendPdfWorker
当 CreatePdfWorker 生成 PDF 后,它会将新生成的 PDF 和收件人加入 SendPdfWorker 队列。
这样,每个 worker 都可以独立工作并异步地从队列中取出,并且您不会与 Sidekiq 的设计选择作斗争。
如果您不想拥有嵌套的 worker,那么在 MailingWorker
中而不是再次排队,如果 PDF 不存在则引发异常。
此外,配置 worker 重试选项,这样 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