2016-04-17 9 views
2

Ich stieß auf ein Problem, wenn PG nicht synchron ist (bekanntes Problem) (example).Kann ich den Rettungsblock erneut starten, ohne zu beginnen ... Ende?

PG versagt nicht synchron, die Sequenz der ID wird erhöht und der Fehler ActiveRecord::RecordNotUnique wird ausgelöst.

Aber alle hier vorgeschlagenen Lösungen (alles, was ich gefunden habe) vorschlagen einige manuelle Lösungen - entweder einige Operationen in der Konsole, entweder benutzerdefinierte Rake-Task ausführen.

Allerdings finde ich dies unbefriedigend für die Produktion: Jedes Mal, wenn es passiert, erhalten Benutzer 500, während jemand, der Server verwaltet, den Tag operativ retten sollte. (Und nach Testdaten aus irgendeinem Grund wird es in meinem Fall häufig vorkommen).

Also ich möchte lieber ActiveRecord Base-Klasse Patch, um diesen spezifischen Fehler zu fangen und es zu retten.

Ich benutze diese Logik manchmal in der Steuerung:

class ApplicationController < ActionController::Base 

    rescue_from ActionController::ParameterMissing, ActiveRecord::RecordNotFound do |e| 
    # some logic here 
    end 
    end 

aber hier sind Wiederholungs nicht brauchen. Außerdem möchte ich zum Beispiel nicht tief in Affepatching gehen, ohne die Base create-Methode zu überschreiben.

So wie ich das an etwas gedacht:

module ActiveRecord 
    class Base 


     rescue ActiveRecord::RecordNotUnique => e 
     if e.message.include? '_pkey' 
      table =e.message.match(//) #regex to define table 
      ActiveRecord::Base.connection.reset_pk_sequence!(table) 
      retry 
     else 
      raise 
     end 
     end 
    end 

Aber es höchstwahrscheinlich nicht funktioniert, wie ich bin nicht sicher, ob Rails/Ruby verstehen, was genau es erneut zu versuchen gefragt.

Gibt es eine Lösung?

P.S. Eine nicht verwandte Lösung für das Gesamtproblem der Sequenz, die ohne manuelle Befehlszeilenbefehle arbeitet und nicht reservierte Benutzer hat, wird ebenfalls geschätzt.

Antwort

0

Um die Frage zu beantworten, die Sie stellen, nein. rescue kann nur innerhalb eines begin..end Blocks oder Methodenkörpers verwendet werden.

begin 
    bad_method 
rescue SomeException 
    retry 
end 

def some_method 
    bad_method 
rescue SomeException 
    retry 
end 

rescue_from ist nur ein Rahmen Helfer-Methode erstellt, weil, wie indirekt die Ausführung in einem Controller ist.

Um die Frage zu beantworten, sind Sie wirklich fragend, sicher. Sie können create_or_update mit einem rescue/retry überschreiben.

module NonUniquePkeyRecovery 
    def create_or_update(*) 
    super 
    rescue ActiveRecord::RecordNotUnique => e 
    raise unless e.message.include? '_pkey' 
    self.class.connection.reset_pk_sequence!(self.class.table_name) 
    retry 
    end 
end 

ActiveSupport.on_load(:active_record) do 
    include NonUniquePkeyRecovery 
end 
Verwandte Themen