2012-03-12 21 views
5

dla wszystkich poniższych zakładają one:konsekwentna obliczenia atrybutów z systemu kolejkowania

  • szyny v3.0
  • rubin v1.9
  • Resque

Mamy 3 modele:

  • Produkt belongs_to: sku, belongs_to: kategoria
  • Sku has_many: produkty, belongs_to: kategoria
  • Kategoria has_many: produkty, has_many: SKU

Kiedy zaktualizować produkt (powiedzmy, że wyłączenie to) musimy mieć pewne rzeczy związane z odpowiednim sku i kategorią. To samo dotyczy aktualizacji sku.

Jednym ze sposobów osiągnięcia tego jest after_save dla każdego modelu, który wyzwala zdarzenia aktualizacji innych modeli.

przykład:

products.each(&:disable!) 
# after_save triggers self.sku.products_updated 
# and self.category.products_updated (self is product) 

Teraz, jeśli mamy 5000 produktów jesteśmy w leczeniu. Ta sama kategoria może zostać zaktualizowana setki razy i przejąć bazę danych podczas tego procesu.

Mamy również ładny system kolejkowania, więc bardziej realistyczny sposób aktualizacji produktów będzie products.each(&:queue_disable!), który po prostu wrzucił 5000 nowych zadań do kolejki pracy. Problem aktualizacji kategorii 5000 nadal istnieje.

Czy istnieje sposób na uniknięcie tych wszystkich aktualizacji na db?

W jaki sposób można połączyć wszystkie kategorie. Products_updated dla każdej kategorii w kolejce?

+0

Dlaczego musisz aktualizować kategorię po zmianie produktu? Czy jest to przeciwna średnia cena, czy co? Jeśli tak, upuść licznik pamięci podręcznej i oblicz go, kiedy jest potrzebny, lub użyj http://redis.io/. –

Odpowiedz

0

Wykonaj zależne aktualizacje w pojedynczych wywołaniach SQL. #update_all zaktualizuje wiele rekordów jednocześnie. Na przykład,

W after_update zwrotnego, zaktualizować wszystkie zależne od wartości kolumny:

class Category 
    after_update :update_dependent_products 

    def update_dependent_products 
    products.update_all(disabled: disabled?) if disabled_changed? 
    end 
end 

Jeśli to zbyt wolno, przesuń go w Resque pracy:

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 

Wykonaj podobne rzeczy dla wywołania zwrotne innego modelu.

+0

Co próbuję zrobić, działa odwrotnie: aktualizuję kilka produktów i każda aktualizacja musi być propagowana do tej kategorii, ale lepiej będzie, jeśli wszystkie aktualizacje produktu zostaną wykonane najpierw, a potem tylko jedna aktualizacja dla każdej z kategorii, których dotyczy problem . – Kostas

+0

OK Nie rozumiałem tego, o co prosiłeś. Dodałem kolejną odpowiedź i zostawię tę. – tee

2

Można zapewnić aktualizację pojedynczej kategorii dla wszystkich produktów za pomocą kilku wtyczek Resque: Resque Unique Job i Resque Scheduler.

Opóźnij wykonanie zadania, aby nieznacznie zaktualizować kategorię (jednak zajmuje to zwykle wywołanie wszystkich aktualizacji produktu) i upewnij się, że każde zadanie jest unikalne, włączając moduł unikatowej pracy. Unikalna praca używa parametrów zadania, więc jeśli spróbujesz umieścić w kolejce 2 zadania o ID kategorii 123, zignoruje drugą, ponieważ zadanie jest już w kolejce.