2016-07-19 5 views
0

Ich habe vor kurzem das Problem von meinem DB mit Adaptive Server connection timed out ziemlich oft konfrontiert, nachdem ich versuche, ein ActiveRecord-Modell zu speichern.RoR: Der richtige Weg eine DB Ausnahme beim Speichern zu retten?

Wenn ich versuche, rescue diesen fehlgeschlagenen Versuch und das Objekt erneut zu speichern, bekomme ich ActiveRecord::StaleObjectError, so muss ich das Objekt von Anfang an gespeichert werden, die eine recht teure Prozedur sein kann.

Was ist der richtige Weg, um diese Situation auf der App-Seite zu behandeln, da ich die DB-Leistung in keiner Weise beeinflussen kann?

+0

'ActiveRecord :: StaleObjectError' wird gesendet, wenn optimistisches Sperren vorhanden ist. Sind Sie sicher, dass nicht versucht wird, den Datensatz parallel zu ändern? –

+0

@NicNilov, ja, das ist sicher. – svz

Antwort

0

reload ist, was Sie

begin 
    object.save 
rescue 
    object.reload.save 
end 

so etwas wollen. hier sind die docs für sie:

http://apidock.com/rails/ActiveRecord/Persistence/reload

+0

Nun, darüber habe ich geschrieben. Sobald ich neu geladen habe, bekomme ich das Objekt in einem Zustand, der in der DB persistiert wurde, bevor ich irgendwelche Änderungen daran vorgenommen habe, also muss ich den ganzen Prozess noch einmal durchlaufen und das ist was ich vermeiden möchte. – svz

+0

Okay, aus irgendeinem Grund war mir nicht klar, dass Sie nur ein grundlegendes Reload versucht haben oder dass diese spezielle Korrektur unerwünscht war. Außerdem ist in Ihrer Frage nicht klar, warum es teuer ist, das Objekt neu zu erstellen, oder warum Sie das Objekt im Speicher von Grund auf neu erstellen müssen. – WattsInABox

+0

Nun, es ist teuer, nicht das Objekt selbst neu zu erstellen, aber sein neuer Zustand verursacht, dass es einige ziemlich schwere Berechnung und Netzwerkinteraktion erfordert. Ich speichere die Ergebnisse möglicherweise an einem anderen Ort, bevor ich sie auf das Modell anwende, aber das sieht eher wie ein Workaround aus als eine Lösung für mich. Ich möchte wissen, wie man damit auf eine "ActiveRecord" Art und Weise umgehen kann. – svz

0

Der Adaptive Server connection timed out Fehler zurückzuführen ist, der die Aufzeichnung zu lange dauert aktualisieren. Eine Möglichkeit, das zu behandeln ist, die Anweisung Timeout in database.yml zu erhöhen:

timeout: 10000 # milliseconds, default is 5000 

Das ist nicht die Frage direkt nicht ansprechen, sondern könnte dazu beitragen, die Häufigkeit des Problems zu senken. Wie in Active Record Query Interface Guide beschrieben, funktioniert optimistisches Sperren nur, wenn das Feld lock_version in der Tabelle vorhanden ist. Es ist nicht klar, ob Sie das Sperren an erster Stelle benötigen, aber Ihre Rails haben es eindeutig aktiviert und funktionieren.

Da der Wert von lock_version das einzige ist, was die ActiveRecord::StaleObjectError auslöst, könnten Sie das bei Ihrem zweiten Speicherversuch manipulieren. Der einfachste Weg wäre den neuesten Wert aus der Datenbank abfragen und Ihr Objekt entsprechend aktualisieren:

lock_version = Model.where(id: model.id).pluck(:lock_version).first 
model.lock_version = lock_version 

# then attempt to save again 

model.save! 

Beachten Sie, dass dies den Datenbank-Status mit den Änderungen neu zu schreiben, unabhängig von jedem parallel gemacht Modifikation, den Sieg über den Zweck der Verriegelung .

Having said that, es ist ein bisschen fischig, dass locking_version ändert sich, wenn das Update ausläuft. Es lohnt sich, es zu erforschen, um zu sehen, warum genau das passiert. Sie sollten zumindest sicherstellen, dass das Update in eine Transaktion eingebettet wird, die das Problem möglicherweise alleine beheben kann.