每当我使用 capistrano 或 run 部署时cap production delayed_job:restart
,我最终都会使当前运行的延迟作业行保持锁定状态。
delay_job 进程成功停止,新的delayed_job 进程启动,新的行被新进程锁定。问题是最后一个进程的行仍然坐在那里并标记为锁定。所以我必须手动进入数据库,删除行,然后手动将该作业添加回队列中,以便新的delayed_job 进程到达。
有没有办法让数据库清理和上一个作业的重新排队自动发生?
每当我使用 capistrano 或 run 部署时cap production delayed_job:restart
,我最终都会使当前运行的延迟作业行保持锁定状态。
delay_job 进程成功停止,新的delayed_job 进程启动,新的行被新进程锁定。问题是最后一个进程的行仍然坐在那里并标记为锁定。所以我必须手动进入数据库,删除行,然后手动将该作业添加回队列中,以便新的delayed_job 进程到达。
有没有办法让数据库清理和上一个作业的重新排队自动发生?
我也有同样的问题。每当作业被强行杀死时,就会发生这种情况。部分问题是工作进程由守护进程 gem 管理,而不是 delay_job 本身。我目前正在研究解决此问题的方法,例如:
如果我想出一个解决方案,我会在这里发帖。
SIGINT
.@约翰卡尼是正确的。简而言之,所有delayed_job
工作人员在重新部署时都会收到类似SIGINT
(很好的中断)的信息。delayed_job
默认情况下,worker 将完成他们当前的工作(如果他们正在从事一项工作),然后优雅地终止。
但是,如果他们正在处理的工作是一项运行时间较长的工作,那么守护程序管理器会等待一段时间,然后才会感到烦恼并发送更严重的中断信号,例如 a SIGTERM
or SIGKILL
。这个等待时间和发送的内容实际上取决于您的设置和配置。
当这种情况发生时,delayed_job
工人会立即被杀死,而无法完成它正在处理的工作,甚至无法自行清理并将该工作标记为不再锁定。
这最终导致标记为“锁定”但锁定到不再存在的进程/工作人员的“搁浅”作业。不好。
这是问题的症结所在,也是正在发生的事情。为了解决这个问题,您有两个主要选择,具体取决于您的工作(我们同时使用):
您可以通过将raise_signal_exceptions
配置设置为:term
或来做到这一点true
:
Delayed::Worker.raise_signal_exceptions = :term
此配置选项接受:term
,true
或false
(默认)。您可以在此处阅读有关原始提交的更多信息。
我会先尝试一下:term
,看看是否能解决您的问题。如果没有,您可能需要将其设置为true
.
设置为:term
ortrue
将优雅地引发异常并解锁工作以供其他delayed_job
工作人员接手并开始工作。
将其设置为true
意味着您的delayed_job
员工甚至不会尝试完成他们正在处理的当前工作。他们将立即引发异常,解锁工作并终止自己。
这实际上取决于您的重新部署等。在我们的例子中,我们使用 Cloud66 来处理部署,所以我们只需要使用它们进行配置。但这就是我们的样子:
stop_sequence: int, 172800, term, 90, kill # Allows long-running delayed jobs to finish before being killed (i.e. on redeploy). Sends SIGINT, waits 48 hours, sends SIGTERM, waits 90 seconds, sends SIGKILL.
在重新部署时,这会告诉守护进程管理器对每个工作人员执行以下步骤delayed_job
:
SIGINT
.SIGTERM
,如果工人还活着。SIGKILL
,如果工人还活着。无论如何,这应该可以帮助您走上正确的轨道,为自己正确配置它。
我们通过设置长时间超时以及在SIGTERM
收到 a 时引发异常来使用这两种方法。这确保了如果有一个作业超过了 2 天的限制,它至少会引发一个异常并解锁该作业,从而使我们能够进行调查,而不是仅仅留下一个被锁定到不再存在的进程的搁浅作业。