延迟作业压倒性数据库
Delayed Job Overwhelming DB
我有一种方法可以更新帐户的所有 DNS 记录,每条记录有 1 个延迟作业。有很多工作人员和队列,这对于快速完成其他工作非常有用,但是这个特定的工作很快完成并且使数据库不堪重负。因为每个作业都需要 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 时,延迟的作业 table 充斥着数万个作业,工作人员开始处理它们。工作人员和队列太多,即使设置最低优先级也会使数据库不堪重负,其他请求也会受到影响。
这是 StaggerJob class:
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
这可能完全可以解决问题,但我想验证这种技术是否合理。
原来这些作业的优先级设置为 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
这最终会在作业外而不是作业内暂停。更好!
我有一种方法可以更新帐户的所有 DNS 记录,每条记录有 1 个延迟作业。有很多工作人员和队列,这对于快速完成其他工作非常有用,但是这个特定的工作很快完成并且使数据库不堪重负。因为每个作业都需要 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 时,延迟的作业 table 充斥着数万个作业,工作人员开始处理它们。工作人员和队列太多,即使设置最低优先级也会使数据库不堪重负,其他请求也会受到影响。
这是 StaggerJob class:
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
这可能完全可以解决问题,但我想验证这种技术是否合理。
原来这些作业的优先级设置为 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
这最终会在作业外而不是作业内暂停。更好!