对于以下所有假设:
我们有3个型号:
当我们更新产品时(假设我们禁用它),我们需要在相关的sku和类别中发生一些事情。更新sku时也是如此。
正确的实现此目的的方法是在每个模型上都有一个after_save
来触发其他模型的更新事件。
示例:
products.each(&:disable!)
# after_save triggers self.sku.products_updated
# and self.category.products_updated (self is product)
现在,如果我们有5000种产品,我们就可以享用。相同的类别可能会更新数百次,并在执行此操作时占用数据库。
我们还有一个很好的排队系统,所以更实际的更新产品的方式是products.each(&:queue_disable!)
,它只会将5000个新任务投入工作队列。但是仍然存在5000类别更新的问题。
有没有办法避免db上的所有更新?
我们如何连接队列中每个类别的所有category.products_updated?
答案 0 :(得分:2)
您可以使用一对Resque插件确保所有产品的单一类别更新:Resque Unique Job和Resque Scheduler。
延迟执行作业以稍微更新类别(无论多长时间通常调用所有产品更新)并通过包含唯一作业模块来确保每个作业都是唯一的。唯一作业使用作业的参数,因此如果您尝试使用category_id 123对2个作业进行排队,则会忽略第2个作业,因为作业已经排队。
class Product
after_save :queue_category_update
def queue_category_update
Resque.enqueue_at(1.minute.from_now, Jobs::UpdateCategory, category.id) if need_to_update_category?
end
end
module Jobs
module UpdateCategory
include Resque::Plugins::UniqueJob
def self.perform(category_id)
category = Category.find_by_id(category_id)
category.update_some_stuff if category
end
end
end
答案 1 :(得分:0)
在单个SQL调用中执行依赖更新。 #update_all会一次更新多条记录。例如,
在after_update回调中,更新所有相关列值:
class Category
after_update :update_dependent_products
def update_dependent_products
products.update_all(disabled: disabled?) if disabled_changed?
end
end
如果这太慢,请将其移至resque工作中:
class Category
after_update :queue_update_dependent_products
def update_dependent_products
products.update_all(disabled: disabled?) if disabled_changed?
end
def queue_update_dependent_products
Resque.enqueue(Jobs::UpdateCategoryDependencies, self.id) if disabled_changed?
end
end
class Jobs::UpdateCategoryDependencies
def self.perform(category_id)
category = Category.find_by_id(category_id)
category.update_dependent_products if category
end
end
为其他模型回调做类似的事情。