延迟工作压倒性数据库

时间:2015-12-28 18:38:47

标签: ruby-on-rails-4 delayed-job

我有一种方法可以更新每个记录的1个延迟作业的帐户的所有DNS记录。有很多工作人员和队列非常适合快速完成其他工作,但这项特殊工作很快就完成了并且压倒了数据库。由于每个作业都需要DNS来解决,因此很难将其移动到收集信息然后写入一次的进程。所以我正在寻找一种方法来摆脱延迟的工作。

据我所知,只需在after方法中使用sleep(0.1)即可。我想知道是否有其他人专门处理过这种情况并解决了它。

我已经创建了一个自定义作业来测试一些不同的想法。这是一些示例代码:

def update_dns
  Account.active.find_each do |account|
    account.domains.where('processed IS NULL').find_each do |domain|
      begin
        Delayed::Job.enqueue StaggerJob.new(self.id)
      rescue Exception => e
        self.domain_logger.error "Unable to update DNS for #{domain.name} (id=#{domain.id})"
        self.domain_logger.error e.message
        self.domain_logger.error e.backtrace
      end
    end
  end
end

当一个cron作业调用Domain.update_dns时,延迟的作业表充斥着数以万计的作业,并且工作人员开始通过它们。有这么多的工作人员和队列,即使设置最低优先级也会压倒数据库,其他请求也会受到影响。

这是StaggerJob类:

class StaggerJob < Struct.new(:domain_id)

  def perform
    domain.fetch_dns_job
  end

  def enqueue(job)
    job.account_id      = domain.account_id
    job.owner           = domain
    job.priority        = 10 # lowest
    job.save
  end

  def after(job)
    # Sleep to avoid overwhelming the DB
    sleep(0.1)
  end

  private
    def domain
      @domain ||= Domain.find self.domain_id
    end

end

这可能完全可以解决问题,但我想验证这种技术是否合理。

1 个答案:

答案 0 :(得分:0)

事实证明,这些工作的优先级设置为0(最高)。设置为10(最低)有帮助。在after方法中工作会有效,但是有更好的方法。

Delayed::Job.enqueue StaggerJob.new(domain.id, :fetch_dns!), run_at: (Time.now + (0.2*counter).seconds) # stagger by 0.2 seconds

这最终会暂停工作而不是内部。更好!