2009-08-27 10 views
10

Ich habe meine eigene Middleware geschrieben, um einen API-Endpunkt für unsere Anwendung bereitzustellen. Die Middleware lädt Klassen, die die API-Methoden bereitstellen, und leitet die Anforderung an die entsprechende Klasse/Methode weiter. Die Klassen werden dynamisch über String#constantize geladen.Nachladen der Klasse stoppt nach nicht abgefangener Ausnahme in benutzerdefinierten Middleware

Während des Entwicklungsmodus werden die Klassen automatisch neu geladen. Wenn es jedoch eine nicht abgefangene Ausnahme gibt, die anschließend von der Failsafe-Middleware behandelt wird, funktioniert das automatische Neuladen nicht mehr. constantize wird immer noch aufgerufen, aber es scheint die alte Klasse zurückzugeben.

Es scheint, dass es noch etwas gibt, das Klassen entlädt, und eine nicht abgefangene Ausnahme bricht es. Was könnte das sein?

Ausführen von Ruby 1.8.7, Rails 2.3.3 und Thin 1.2.2.

+0

Ich habe auch dieses Problem. –

Antwort

0

Rails speichert viele Klassen, entlädt sie und lädt sie im Entwicklungsmodus oder wenn config.cache_classes auf true gesetzt ist. Hier sind einige Gedanken zum Thema, die auch erklären, wie es funktioniert. http://www.spacevatican.org/2008/9/28/required-or-not/

Um nicht zu sagen, dass Sie es falsch machen, aber Überladung String # constalize scheint wie eine hacky Weg, um Ihren Code neu zu laden. Haben Sie in Erwägung zu ziehen, einen App Server in Ihrer Entwicklung mit so etwas wie watchr zu starten und neu zu starten, wenn Sie Dateien in Ihrem API-Teilbaum speichern? https://github.com/mynyml/watchr/

Auch für einige zufällige Ideen, wie Debug zu fördern, diese Antwort finden Sie unter: https://stackoverflow.com/a/7907289/632022

1

denke ich, dieser Effekt von der Art und Weise kommt ActionController::Reloader geschrieben. Hier ist ActionController::Reloader#call von 2.3.3, beachten Sie den Kommentar:

def call(env) 
    Dispatcher.reload_application 
    status, headers, body = @app.call(env) 
    # We do not want to call 'cleanup_application' in an ensure block 
    # because the returned Rack response body may lazily generate its data. This 
    # is for example the case if one calls 
    # 
    # render :text => lambda { ... code here which refers to application models ... } 
    # 
    # in an ActionController. 
    # 
    # Instead, we will want to cleanup the application code after the request is 
    # completely finished. So we wrap the body in a BodyWrapper class so that 
    # when the Rack handler calls #close during the end of the request, we get to 
    # run our cleanup code. 
    [status, headers, BodyWrapper.new(body)] 
end 

Dispatcher.reload_application entfernt nicht automatisch geladen Konstanten, Dispatcher.cleanup_application tut. BodyWrapper#close mit möglichen Ausnahmen in Verstand geschrieben:

def close 
    @body.close if @body.respond_to?(:close) 
ensure 
    Dispatcher.cleanup_application 
end 

jedoch dies nicht hilft, denn wenn @app.call in ActionController::Reloader#call eine Ausnahme auslöst, BodyWrapper nicht instanziiert erhält, und Dispatcher.cleanup_application gecallt nicht.

Stellen Sie sich folgendes Szenario vor:

  • ich Änderungen in einer meiner Dateien abspeichern, die API-Aufruf beeinflusst
  • ich API-Aufruf getroffen und Fehler sehen, die an dieser Stelle alle Dateien einschließlich der mit einem Fehler aren ‚t entladen
  • ich einen codefix machen und schlug die gleiche API-Aufruf zu überprüfen, ob es
  • arbeitete
  • Anruf die gleiche Art und Weise weitergeleitet wird nach wie vor zu den alten Klassen/Objekte/Module. Dies wirft gleiche Fehler und läßt wieder geladen Konstanten im Speicher

Dies geschieht nicht, wenn traditionelle Controller Fehler erhöhen, weil die von ActionController::Rescue behandelt werden. Solche Ausnahmen treffen nicht ActionController::Reloader.

Simplest Lösung Ausweich rescue-Klausel in API-Routing-Middleware zu setzen, eine gewisse Variation davon wäre:

def call(env) 
    # route API call 
resuce Exception 
    Dispatcher.cleanup_application 
    raise 
end 

Hinweis, dass dies meine Antwort auf 3 Jahre alte Frage, und ich folgte Call-Stack von 2.3.3 . Neuere Versionen von Schienen können die Dinge anders handhaben.

Verwandte Themen