Перезагрузка класса останавливается после необработанного исключения в пользовательском промежуточном программном обеспечении - PullRequest
10 голосов
/ 27 августа 2009

Я написал свое собственное промежуточное ПО для предоставления конечной точки API для нашего приложения. Промежуточное программное обеспечение загружает классы, предоставляющие методы API, и направляет запрос в соответствующий класс / метод. Классы загружаются динамически через String#constantize.

При работе в режиме разработки классы автоматически перезагружаются. Однако, если есть необработанное исключение, которое впоследствии обрабатывается промежуточным программным обеспечением Failsafe, автоматическая перезагрузка перестает работать. constantize все еще вызывается, но, похоже, возвращает старый класс.

Может показаться, что есть что-то еще, что выгружает классы, а необработанное исключение нарушает его. Что бы это могло быть?

Запуск Ruby 1.8.7, Rails 2.3.3 и Thin 1.2.2.

Ответы [ 2 ]

1 голос
/ 22 августа 2012

Я думаю, что этот эффект происходит от того, как написано ActionController::Reloader. Вот ActionController::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_application делает. BodyWrapper#close написано с учетом возможных исключений:

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

Однако это не помогает, потому что если @app.call в ActionController::Reloader#call выдает исключение, BodyWrapper не создается, а Dispatcher.cleanup_application не вызывается.

Представьте себе следующий сценарий:

  • Я делаю изменения в одном из моих файлов, что влияет на вызов API
  • Я нажимаю вызов API и вижу ошибку, в этот момент все файлы, включая файл с ошибкой, не выгружаются
  • Я делаю кодовое исправление и нажимаю тот же вызов API, чтобы проверить, сработало ли оно
  • вызов направляется так же, как и раньше, к старым классам / объектам / модулям. Это выдает ту же ошибку и снова оставляет загруженные константы в памяти

Этого не происходит, когда традиционные контроллеры генерируют ошибки, потому что они обрабатываются ActionController::Rescue. Такие исключения не бьют ActionController::Reloader.

Самое простое решение - поместить аварийное спасательное предложение в промежуточное ПО маршрутизации API, некоторые варианты этого:

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

Обратите внимание, что это мой ответ на трехлетний вопрос, и я следовал за стеком вызовов 2.3.3. Более новые версии рельсов могут обрабатывать вещи по-разному.

0 голосов
/ 20 августа 2012

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

...