多租户resque,并避免一个租户堵塞队列

时间:2015-11-14 12:20:54

标签: redis background-process resque php-resque

我们有一个运行resque的多租户应用进行后台处理。

我们偶尔遇到的问题是,单个租户在很短的时间内完成很多的后台工作。这基本上堵塞了一段时间 - 在我们处理这个单一租户的积压工作时,其他每个租户的工作都被延迟了。

是的,我们可以添加更多工人。但这不是一个真正的解决方案"它更像是一个创可贴,但仍会导致其他租户的延迟 - 只是因为我们处理得更快而延迟更短。

是否有更多多租户友好的方式使用resque?或者更多的多租户友好背景队列?

我们正在考虑:

  • 每个租户使用一个队列,每个租户使用一个工作人员(动态创建队列?)
  • 修改resque,使其以某种方式循环通过每个租户的队列

我们只是想知道我们是否有一些错过/更好的方式...

1 个答案:

答案 0 :(得分:0)

您可以使用Rails.cache维护每个参与者的临时作业计数器,并根据活动作业的数量将作业分配到不同的队列。

您需要将作业子类化以支持不同的队列,并编写一个解析为该作业的正确类的方法。类似的东西:

class Worker

   cattr_acessor :tenant_id

   class Worker::Low < Worker
     @queue = :low
   end

   class Worker::High < Worker
     @queue = :high
   end

   def self.queued
      "#{name}::#{resolved_queue(tenant_id)}".constantize
   end

   def self.resolved_queue tenant_id
     count = job_count(tenant_id)
     if count > 1000
       'Low'
     else
       'High'
     end
   end

   def self.cache_key tenant_id
     "job_count/#{tenant_id}"
   end

   def self.job_count tenant_id
     Rails.cache.fetch(cache_key(tenant_id)){0}
   end

   def self.job_count_increment tenant_id
     Rails.cache.fetch(cache_key(tenant_id)){0}
     Rails.increment(cache_key(tenant_id)){0}
   end

   def self.job_count_decrement tenant_id
     count = Rails.cache.fetch(cache_key(tenant_id)){0}
     Rails.decrement(cache_key(tenant_id)){0} if count > 0
   end
end

然后在运行工作人员时调用Worker.queued(tenant_id).perform,并确保在应用程序中的Worker.tenant_id上设置了before_filters。有关队列和优先级的更多信息,请参阅Resque Priorities and Queue Lists

您应该在作业队列中调用增量并从作业中减少。

丑陋,但可行。

可以通过一些元编程使其更加干燥 - 将这些方法提取到模块中,然后确保在模块include上生成队列子类。