我们有与其他应用程序同步的Rails应用程序。它在后台发生。基本上,每次此作业仅同步所有数据时,此刻它确实很慢,我们正在寻求通过使用并行性来加快处理速度。
目前基本上是这样的:
accounts.each { |a| sync_account(a) }
我们希望它看起来像这样:
accounts.each { |a| SyncAccountJob.perform_later(a) }
确切地说,我们要为此使用后台队列。首先,我们希望每个帐户使用一份工作(我们有许多需要同步的帐户)。这里的问题是如何防止队列多次获得相同的作业?
例如,如果我们每小时安排一次工作,有时某些帐户尚未同步,则将安排新工作(对不起,我的英语)。
你会做什么?
我们认为我们应该在帐户表中保留一个已创建作业的ID,并在再次计划该作业之前检查该作业是否不存在。
其他问题是我们使用什么系统:delay_job(已由邮件使用)或sidekiq?
另一个问题:“僵尸”工作。例如,假设我安排了一些作业(delayed_job),然后工作人员开始处理它。现在已锁定。然后服务器崩溃,因此作业仍被锁定,但没有任何处理。 delay_job / sidekiq是否可以自行解决此问题,还是应该写一些更干净的文件?
对于该主题的任何评论或故事,我将不胜感激。
答案 0 :(得分:2)
如果我们每小时安排工作
在这种情况下,您可以使用sidekiq-cron。它将确保不会同时运行相同的作业。 当然,存储ID的方法也可以使用。
关于僵尸工作-恕我直言,这应该不是一个大问题。您的服务器不会定期崩溃,不是吗?如有任何问题,您始终可以在Web GUI或控制台中清除内容。
答案 1 :(得分:2)
首先,您要使用异步(而不是并行性)细微的差异来加快流程。 :)
第二,听起来好像要解决三个主要问题:
从历史上看,我已经将Resque用于此类事情-但我敢肯定还有很多选择。
您将执行以下操作:
accounts.each { |a| Resque.enqueue(SyncAccount, a) }
为确保它们在将来的某个时刻运行,您可以使用 cron 或 resque Scheduler 。
就确保作业的唯一性而言,您可以使用某种缓存层,例如 Redis ,在其上存储哈希函数的输出,其中与您用于创建作业的帐户相关联的参数,您可以在排队作业之前查询该参数,并在完成作业后写入redis。
为了避免Zombie Jobs,大多数情况下,我建议将您的工作逻辑包装在合理的超时块中,是的,请使用某种清洁剂修剪死掉的工作不在队列中。
答案 2 :(得分:0)
让我们看看。
延迟的作业或Sidekiq:这取决于应用程序的性质。由于您已经具有用于作业排队的后端系统,因此可以很好地使用它。每个系统都有差异(正负),因此最终取决于您的选择。举一个例子,如果您的应用程序是数据库密集型应用程序,那么最好避免delay_jobs。
每个案件一名DJ:我愿意。
i)在您的帐户表中添加一列。说'sync_status'。在将同步作业排队之前,将状态设置为“进行中”。
ii)之后,编写一个自定义作业进行同步。既然您已经准备好了业务逻辑代码,这应该不难。同步完成后,您可以将状态更改为“完成”或恢复为“就绪”。
iii)这样,仅当该帐户的“ sync_status”完成/就绪时,您才可以将作业排队。
示例:
Delayed::Job.enqueue(CustomSyncJob.new()) if account.ready_to_sync?
在custom_sync.rb中,最后:
account.status = 'ready'
account.save
处理信号:您的应用程序绝不应该崩溃,并且您的代码应确保崩溃。但是要优雅地杀死DJ,您可以添加以下设置:
Delayed :: Worker.raise_signal_exceptions =:term
它将引发SignalException。 DJ会通过清除locked_by列来妥善处理此问题。
希望这会有所帮助。干杯。