10

アプリケーションに API エンドポイントを提供する独自のミドルウェアを作成しました。ミドルウェアは、API メソッドを提供するクラスをロードし、リクエストを適切なクラス/メソッドにルーティングします。クラスは、 を通じて動的にロードされますString#constantize

開発モードで実行している間、クラスは自動的に再ロードされます。ただし、キャッチされない例外が発生した場合 (後で Failsafe ミドルウェアによって処理される場合)、自動再読み込みは機能しなくなります。constantizeまだ呼び出されていますが、古いクラスを返すようです。

クラスをアンロードする何かが他にあるように見え、キャッチされない例外がそれを壊します。これは何ですか?

Ruby 1.8.7、Rails 2.3.3、および Thin 1.2.2 を実行しています。

4

2 に答える 2

1

この効果は書き方によるものだと思いますActionController::ReloaderActionController::Reloader#callこれは 2.3.3のものです。コメントに注意してください。

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自動ロードされた定数を削除しませんDispatcher.cleanup_applicationBodyWrapper#close考えられる例外を念頭に置いて書かれています。

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

ただし、例外がスローされた場合@app.call、インスタンス化されず、呼び出されないため、これは役に立ちません。ActionController::Reloader#callBodyWrapperDispatcher.cleanup_application

次のシナリオを想像してください。

  • API 呼び出しに影響するファイルの 1 つを変更します
  • API 呼び出しを実行するとエラーが表示されます。この時点で、バグのあるファイルを含むすべてのファイルがアンロードされません。
  • コード修正を行い、同じAPI 呼び出しを実行して、機能するかどうかを確認します
  • 呼び出しは、以前と同じ方法で、古いクラス/オブジェクト/モジュールにルーティングされます。これは同じエラーをスローし、ロードされた定数をメモリに残します

これは、従来のコントローラがエラーを発生させた場合には発生しません。これらは によって処理されるためActionController::Rescueです。このような例外はヒットしませんActionController::Reloader

最も簡単な解決策は、フォールバック レスキュー句を API ルーティング ミドルウェアに配置することです。これにはいくつかのバリエーションがあります。

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

これは 3 年前の質問に対する私の回答であり、2.3.3 のコール スタックに従っていることに注意してください。レールの新しいバージョンでは、処理が異なる場合があります。

于 2012-08-22T13:52:16.237 に答える
0

Rails は多くのクラスをキャッシュし、開発モードで、または config.cache_classes が true に設定されている場合、それらをアンロードして再ロードします。ここでは、トピックに関するいくつかの考えと、それがどのように機能するかを説明しています。 http://www.spacevatican.org/2008/9/28/required-or-not/

あなたが間違っていると言うつもりはありませんが、String#constantize をオーバーロードすることは、コードをリロードするためのハックな方法のように思えます。watchr のようなものを使用して開発中のアプリ サーバーを実行し、API サブツリーにファイルを保存するときに再起動することを検討しましたか? https://github.com/mynyml/watchr/

また、さらにデバッグする方法に関するランダムなアイデアについては、次の回答を確認してください: https://stackoverflow.com/a/7907289/632022

于 2012-08-19T22:24:06.877 に答える