2009-08-27 17 views
10

Pisałem własne oprogramowanie warstwy pośredniej, aby zapewnić punkt końcowy API do naszej aplikacji. Klasa pośrednia ładuje klasy, które udostępniają metody API, i kieruje żądanie do odpowiedniej klasy/metody. Klasy są ładowane dynamicznie przez String#constantize.Klasa przeładunkowa zatrzymuje się po przechwycony wyjątek w niestandardowym middleware

Podczas pracy w trybie rozwoju, zajęcia są automatycznie przeładowana. Jednakże, jeśli nie jest przechwycony wyjątkiem - które są następnie przetwarzane przez Fail-Safe pośredniczącego - automatyczne przeładunkowa przestaje działać. constantize jest wciąż wywoływana, ale wydaje się, że zwraca starą klasę.

Wydaje się, że jest coś innego, co rozładowuje klas, a przechwycony wyjątek łamie go. Co to może być?

Running Ruby 1.8.7, Rails 2.3.3 i 1.2.2 cienki.

+0

Mam również ten problem. –

Odpowiedz

0

Szyny buforuje wiele klas i rozładowuje i ładuje je w trybie rozwoju lub gdy config.cache_classes jest ustawiona na wartość true. Oto kilka myśli na ten temat, które również wyjaśniają, jak to działa. http://www.spacevatican.org/2008/9/28/required-or-not/

Nie mówię, że robisz to źle, ale przeciążenie String # constantize wydaje się być zręcznym sposobem na przeładowanie twojego kodu. Czy rozważyłeś użycie czegoś takiego jak watchr, aby uruchomić serwer aplikacji w fazie rozwoju i uruchomić go ponownie podczas zapisywania plików w poddrzewie interfejsu API? https://github.com/mynyml/watchr/

Ponadto, dla niektórych przypadkowych pomysłów na dalsze debug, sprawdź tę odpowiedź: https://stackoverflow.com/a/7907289/632022

1

myślę, że to efekt pochodzi od sposobu ActionController::Reloader jest napisane. Oto ActionController::Reloader#call z 2.3.3, należy zwrócić uwagę na komentarz:

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 nie usuwa auto załadowane stałe, Dispatcher.cleanup_application robi. BodyWrapper#close jest napisany z możliwymi wyjątkami pamiętać:

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

Jednak to nie pomoże, bo jeśli @app.call w ActionController::Reloader#call zgłasza wyjątek, BodyWrapper nie uzyskać uruchamianiu i Dispatcher.cleanup_application nie zostanie wywołana.

Wyobraźmy sobie następujący scenariusz:

  • dokonać zmian w jednym z moich plików, które wpływa na wywołanie API
  • uderzę wywołania API i widzieć błędu, w tym momencie wszystkie pliki w tym jeden z błędem aren „t rozładowywane
  • zrobię codefix i uderzył tego samego połączenia API, aby sprawdzić, czy to zadziałało
  • wezwanie zostanie poprowadzony w taki sam sposób jak poprzednio, do starych zajęć/przedmiotów/modułów. Powoduje to ten sam błąd i ponownie pozostawia załadowane stałe w pamięci

Nie dzieje się tak, gdy tradycyjne kontrolery podnoszą błędy, ponieważ są obsługiwane przez ActionController::Rescue. Takie wyjątki nie trafiają na ActionController::Reloader.

Najprostszym rozwiązaniem byłoby umieścić klauzulę zastępczej ratunkowego do API routingu middleware, jakąś odmianę tego:

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

Należy pamiętać, że to jest moja odpowiedź na pytanie 3-letniego, a ja za rozmowę stos 2.3.3 . Nowsze wersje szyn mogą obsługiwać różne rzeczy.

Powiązane problemy