2009-08-27 8 views
10

Ho scritto il mio middleware per fornire un endpoint API alla nostra applicazione. Il middleware carica le classi che forniscono i metodi API e indirizza la richiesta alla classe/metodo appropriato. Le classi vengono caricate dinamicamente tramite String#constantize.Il ripristino della classe si interrompe dopo l'eccezione non risolta nel middleware personalizzato

Durante l'esecuzione in modalità di sviluppo, le classi vengono ricaricate automaticamente. Tuttavia, se c'è un'eccezione non rilevata - che viene successivamente gestita dal middleware Failsafe - il caricamento automatico smette di funzionare. constantize viene ancora chiamato ma sembra restituire la vecchia classe.

Sembra che ci sia qualcos'altro che scarica le classi e un'eccezione non rilevata la spezza. Cosa potrebbe essere?

Esecuzione di Ruby 1.8.7, Rails 2.3.3 e Thin 1.2.2.

+0

Ho anche questo problema. –

risposta

0

Rails memorizza nella cache molte classi e scarica e le ricarica in modalità sviluppo o quando config.cache_classes è impostato su true. Ecco alcuni pensieri sull'argomento che spiegano anche come funziona. http://www.spacevatican.org/2008/9/28/required-or-not/

Non dirti che stai sbagliando, ma il sovraccarico di String # constantize sembra un modo hacky per ricaricare il tuo codice. Hai in mente di utilizzare qualcosa come watchr per eseguire il tuo server delle applicazioni in fase di sviluppo e riavviarlo quando salvi i file nella sottostruttura API? https://github.com/mynyml/watchr/

Inoltre, per alcune idee casuali su come favorire il debug, verificare questa risposta: https://stackoverflow.com/a/7907289/632022

1

Penso che questo effetto deriva dal modo in cui è scritto ActionController::Reloader. Ecco ActionController::Reloader#call da 2.3.3, nota il commento:

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 non toglie costanti auto-caricato, Dispatcher.cleanup_application fa. BodyWrapper#close è scritto con eventuali eccezioni in mente:

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

Tuttavia, questo non aiuta, perché se @app.call in ActionController::Reloader#call genera un'eccezione, BodyWrapper non ottiene istanziati, e Dispatcher.cleanup_application non viene chiamato.

Immaginate il seguente scenario:

  • posso apportare modifiche in uno dei miei file che colpisce chiamata API
  • mi ha colpito chiamata API e vedere l'errore, a questo punto tutti i file, tra cui quello con un bug aren 't scaricati
  • Faccio un codefix e colpito la stessa chiamata API per verificare se ha funzionato
  • chiamata viene instradata allo stesso modo di prima, a vecchie classi/oggetti/modules. Questo getta stesso errore e ancora lascia costanti caricato in memoria

Ciò non accade quando i controllori tradizionali sollevano errori perché quelli sono gestite dai ActionController::Rescue. Tali eccezioni non hanno colpito ActionController::Reloader.

soluzione più semplice sarebbe quella di mettere clausola rescue fallback in API di routing middleware, qualche variazione di questo:

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

notare che questa è la mia risposta alla domanda di 3 anni e ho seguito chiamata pila di 2.3.3 . Le versioni più recenti dei binari possono gestire le cose in modo diverso.

Problemi correlati