2016-06-02 6 views
0

Ich habe einen Sidekiq Worker, der eine API-Aufruf, analysiert die zurückgegebene JSON und erstellt Objekte (Produkte). Da die Produkte einer Marke gehören und das Produkt json enthält auch die Daten für die Marke, hat der Arbeitnehmer die folgenden Punkte, bevor das Produkt in die Datenbank tatsächlich zu speichern:So erstellen Sie Datensätze gleichzeitig in Postgres mit ActiveRecord und Sidekiq

  1. prüft, ob die Marke in der Datenbank vorhanden, indem Sie ihre Unique api_id (die ID, mit der die Marke aus der API kommt, in der Datenbank gibt es einen eindeutigen Index für diese Spalte);
  2. wenn dies der Fall ist - holen Sie sich die primäre ID;
  3. wenn ist, nicht - es schaffen und erhalten ihre primäre ID

ich dies wie so umgesetzt haben:

def brand_id(brand_json) 
    Brand.where(api_id: brand_json[:api_id]).pluck(:id).first.presence || 
    Brand.create!(name: brand_json[:name], api_id: brand_json[:api_id]).id 
end 

Nach dass der Arbeiter schafft das Produkt mit dem brand_id auf dem geholten gesetzt Ich würde.

Jetzt denke ich von folgendem Szenario:

  1. zwei Arbeiter für zwei Produkte gleichzeitig Daten abzurufen, die zu der gleichen Marke gehören, die ja nicht in der Datenbank vorhanden ist;
  2. Arbeiter 1 man sucht nach der Marke und findet sie nicht;
  3. Kurz danach überprüft der Arbeiter 2 die Marke und findet sie nicht.
  4. Arbeiter 1 erstellt die Marke;

Was passiert nun mit Arbeiter 2? Meine Annahme - es versucht, die Marke zu erstellen, aber ein Fehler auf der Datenbankebene tritt auf, da es bereits einen Datensatz mit der gleichen api_id gibt? (wahrscheinlich ActiveRecord::RecordNotUnique Fehler wird ausgelöst?)

Auch, wie gehe ich mit diesem Fall und diese Art von Fehlern im Zusammenhang mit Sidekiq und ? Sollte ich irgendwie eine tabellenweite Sperre auf der Marken-Tabelle implementieren, um solche Dinge zu verhindern? Wenn ja, dann kann ich nicht gleichzeitig Produkte erstellen, da zu einem bestimmten Zeitpunkt nur ein Mitarbeiter Zugriff auf die Markentabelle hat, die für die Erstellung eines Produkts erforderlich ist.

Oder vielleicht sollte ich meine brand_id(brand_json) Methode in der Transaktion wickeln etwa so:

def brand_id(brand_json) 
    ActiveRecord::Base.transaction do 
    Brand.where(api_id: brand_json[:api_id]).pluck(:id).first.presence || 
    Brand.create!(name: brand_json[:name], api_id: brand_json[:api_id]).id 
    end 
end 

Bitte raten.

Antwort

1
  1. Setzen der eindeutigen Index Bedingungen (gegebenenfalls in Form eines Mehrspaltenindex) in der DB.
  2. Versuchen Sie einfach, das Objekt zu erstellen. Die Datenbank verhindert, dass Sie mehr als einen erstellen.
  3. Nur der Thread, der das ursprüngliche Objekt erfolgreich erstellt hat (es ist keine Ausnahme aufgetreten), kann mit zusätzlicher Verarbeitung fortfahren.
Verwandte Themen