为什么delayed_jobs在出错时会循环?

时间:2011-06-10 15:17:54

标签: ruby-on-rails delayed-job

我有几个场合,其中delayed_jobs将负责发送4千封电子邮件,如果这些电子邮件中有错误(例如,如果没有通话),那么它将重新启动整个过程并尝试发送还有4000封电子邮件。这将继续无限期,直到我手动杀死-9整个过程。

在过去的几年中,我在不同的应用程序中发生了这么多次,我很好奇是否发生过其他任何人。他们做了什么来克服它。

2 个答案:

答案 0 :(得分:10)

延迟作业通常只是在后台进程中由工作程序执行的方法,而不是在应用程序的主线程(Rails应用程序的请求生命周期)期间执行。

如果您阅读“血腥细节”下的documentation for delayed_job,则说明:

  

失败时,作业将在5秒内再次安排+ N ** 4,其中N是重试次数。

     

默认的Worker.max_attempts为25.此后,作业被删除(默认),或者在设置了“failed_at”的数据库中保留。   默认为25次尝试,最后一次重试将在20天后进行,最后一次间隔将近100小时。

听起来你所描述的是delayed_jobs打算运行的方式 - 如果发送4,000封电子邮件的作业在发送3,000封后失败,它就会重新开始。您可能需要跟踪已发送和未发送的内容,因此您的作业可以循环“未发送”电子邮件(或任何适合您的后台进程的信息)。这样,当您发送3,000封电子邮件时,它们会被标记为“已发送”,如果您的作业失败,则会通过加载剩余的1,000封“未发送”电子邮件并尝试发送它们来重新开始。

如果您确实不希望作业在失败时重试,可以将以下代码添加到项目中:

# config/initializers/delayed_job_config.rb
Delayed::Worker.max_attempts = 1

答案 1 :(得分:4)

由于这个原因,我们有一个延迟工作的规则 - 每个工作必须是原子的。如果作业由于某种原因(异常,网络错误等)失败,则必须没有副作用。

对于只修改数据库的作业,解决方案很简单 - 将作业包装在事务中。

对于与外部服务交互的作业(发送电子邮件,点击API等),我们会尝试将每项任务分解为单独的工作。

在您的情况下,我们将创建4000个作业,1个用于发送每封电子邮件。如果其中一些失败,那么他们将继续重试,而不会一遍又一遍地向其他人发送电子邮件。