Refactor Dispatcher callbacks to remove unnecessary Dependencies checks in production environment.
This commit is contained in:
parent
cf04e62127
commit
986aec5dbb
@ -5,6 +5,30 @@ class Dispatcher
|
||||
@@guard = Mutex.new
|
||||
|
||||
class << self
|
||||
def define_dispatcher_callbacks(cache_classes)
|
||||
unless cache_classes
|
||||
# Development mode callbacks
|
||||
before_dispatch :reload_application
|
||||
after_dispatch :cleanup_application
|
||||
end
|
||||
|
||||
# Common callbacks
|
||||
to_prepare :load_application_controller do
|
||||
begin
|
||||
require_dependency 'application' unless defined?(::ApplicationController)
|
||||
rescue LoadError => error
|
||||
raise unless error.message =~ /application\.rb/
|
||||
end
|
||||
end
|
||||
|
||||
if defined?(ActiveRecord)
|
||||
before_dispatch { ActiveRecord::Base.verify_active_connections! }
|
||||
to_prepare(:activerecord_instantiate_observers) { ActiveRecord::Base.instantiate_observers }
|
||||
end
|
||||
|
||||
after_dispatch :flush_logger if defined?(RAILS_DEFAULT_LOGGER) && RAILS_DEFAULT_LOGGER.respond_to?(:flush)
|
||||
end
|
||||
|
||||
# Backward-compatible class method takes CGI-specific args. Deprecated
|
||||
# in favor of Dispatcher.new(output, request, response).dispatch.
|
||||
def dispatch(cgi = nil, session_options = CgiRequest::DEFAULT_SESSION_OPTIONS, output = $stdout)
|
||||
@ -69,23 +93,9 @@ def failsafe_logger
|
||||
cattr_accessor :error_file_path
|
||||
self.error_file_path = Rails.public_path if defined?(Rails.public_path)
|
||||
|
||||
cattr_accessor :unprepared
|
||||
self.unprepared = true
|
||||
|
||||
include ActiveSupport::Callbacks
|
||||
define_callbacks :prepare_dispatch, :before_dispatch, :after_dispatch
|
||||
|
||||
before_dispatch :reload_application
|
||||
before_dispatch :prepare_application
|
||||
after_dispatch :flush_logger
|
||||
after_dispatch :cleanup_application
|
||||
|
||||
if defined? ActiveRecord
|
||||
to_prepare :activerecord_instantiate_observers do
|
||||
ActiveRecord::Base.instantiate_observers
|
||||
end
|
||||
end
|
||||
|
||||
def initialize(output, request = nil, response = nil)
|
||||
@output, @request, @response = output, request, response
|
||||
end
|
||||
@ -114,40 +124,23 @@ def dispatch_cgi(cgi, session_options)
|
||||
end
|
||||
|
||||
def reload_application
|
||||
if Dependencies.load?
|
||||
Routing::Routes.reload
|
||||
self.unprepared = true
|
||||
end
|
||||
end
|
||||
# Run prepare callbacks before every request in development mode
|
||||
run_callbacks :prepare_dispatch
|
||||
|
||||
def prepare_application(force = false)
|
||||
begin
|
||||
require_dependency 'application' unless defined?(::ApplicationController)
|
||||
rescue LoadError => error
|
||||
raise unless error.message =~ /application\.rb/
|
||||
end
|
||||
|
||||
ActiveRecord::Base.verify_active_connections! if defined?(ActiveRecord)
|
||||
|
||||
if unprepared || force
|
||||
run_callbacks :prepare_dispatch
|
||||
ActionView::TemplateFinder.reload! unless ActionView::Base.cache_template_loading
|
||||
self.unprepared = false
|
||||
end
|
||||
Routing::Routes.reload
|
||||
ActionView::TemplateFinder.reload! unless ActionView::Base.cache_template_loading
|
||||
end
|
||||
|
||||
# Cleanup the application by clearing out loaded classes so they can
|
||||
# be reloaded on the next request without restarting the server.
|
||||
def cleanup_application(force = false)
|
||||
if Dependencies.load? || force
|
||||
ActiveRecord::Base.reset_subclasses if defined?(ActiveRecord)
|
||||
Dependencies.clear
|
||||
ActiveRecord::Base.clear_reloadable_connections! if defined?(ActiveRecord)
|
||||
end
|
||||
def cleanup_application
|
||||
ActiveRecord::Base.reset_subclasses if defined?(ActiveRecord)
|
||||
Dependencies.clear
|
||||
ActiveRecord::Base.clear_reloadable_connections! if defined?(ActiveRecord)
|
||||
end
|
||||
|
||||
def flush_logger
|
||||
RAILS_DEFAULT_LOGGER.flush if defined?(RAILS_DEFAULT_LOGGER) && RAILS_DEFAULT_LOGGER.respond_to?(:flush)
|
||||
RAILS_DEFAULT_LOGGER.flush
|
||||
end
|
||||
|
||||
protected
|
||||
|
@ -11,7 +11,13 @@ def setup
|
||||
@output = StringIO.new
|
||||
ENV['REQUEST_METHOD'] = 'GET'
|
||||
|
||||
# Clear callbacks as they are redefined by Dispatcher#define_dispatcher_callbacks
|
||||
Dispatcher.instance_variable_set("@prepare_dispatch_callbacks", ActiveSupport::Callbacks::CallbackChain.new)
|
||||
Dispatcher.instance_variable_set("@before_dispatch_callbacks", ActiveSupport::Callbacks::CallbackChain.new)
|
||||
Dispatcher.instance_variable_set("@after_dispatch_callbacks", ActiveSupport::Callbacks::CallbackChain.new)
|
||||
|
||||
Dispatcher.stubs(:require_dependency)
|
||||
|
||||
@dispatcher = Dispatcher.new(@output)
|
||||
end
|
||||
|
||||
@ -20,17 +26,13 @@ def teardown
|
||||
end
|
||||
|
||||
def test_clears_dependencies_after_dispatch_if_in_loading_mode
|
||||
Dependencies.stubs(:load?).returns(true)
|
||||
|
||||
ActionController::Routing::Routes.expects(:reload).once
|
||||
Dependencies.expects(:clear).once
|
||||
|
||||
dispatch
|
||||
dispatch(@output, false)
|
||||
end
|
||||
|
||||
def test_leaves_dependencies_after_dispatch_if_not_in_loading_mode
|
||||
Dependencies.stubs(:load?).returns(false)
|
||||
|
||||
ActionController::Routing::Routes.expects(:reload).never
|
||||
Dependencies.expects(:clear).never
|
||||
|
||||
@ -51,40 +53,25 @@ def test_failsafe_response
|
||||
assert_equal "Status: 400 Bad Request\r\nContent-Type: text/html\r\n\r\n<html><body><h1>400 Bad Request</h1></body></html>", @output.string
|
||||
end
|
||||
|
||||
def test_reload_application_sets_unprepared_if_loading_dependencies
|
||||
Dependencies.stubs(:load?).returns(false)
|
||||
ActionController::Routing::Routes.expects(:reload).never
|
||||
@dispatcher.unprepared = false
|
||||
@dispatcher.send!(:reload_application)
|
||||
assert !@dispatcher.unprepared
|
||||
|
||||
Dependencies.stubs(:load?).returns(true)
|
||||
ActionController::Routing::Routes.expects(:reload).once
|
||||
@dispatcher.send!(:reload_application)
|
||||
assert @dispatcher.unprepared
|
||||
end
|
||||
|
||||
def test_prepare_application_runs_callbacks_if_unprepared
|
||||
def test_prepare_callbacks
|
||||
a = b = c = nil
|
||||
Dispatcher.to_prepare { |*args| a = b = c = 1 }
|
||||
Dispatcher.to_prepare { |*args| b = c = 2 }
|
||||
Dispatcher.to_prepare { |*args| c = 3 }
|
||||
|
||||
# Skip the callbacks when already prepared.
|
||||
@dispatcher.unprepared = false
|
||||
@dispatcher.send! :prepare_application
|
||||
# Ensure to_prepare callbacks are not run when defined
|
||||
assert_nil a || b || c
|
||||
|
||||
# Perform the callbacks when unprepared.
|
||||
@dispatcher.unprepared = true
|
||||
@dispatcher.send! :prepare_application
|
||||
# Run callbacks
|
||||
@dispatcher.send :run_callbacks, :prepare_dispatch
|
||||
|
||||
assert_equal 1, a
|
||||
assert_equal 2, b
|
||||
assert_equal 3, c
|
||||
|
||||
# But when not :load, make sure they are only run once
|
||||
# Make sure they are only run once
|
||||
a = b = c = nil
|
||||
@dispatcher.send! :prepare_application
|
||||
@dispatcher.send :dispatch
|
||||
assert_nil a || b || c
|
||||
end
|
||||
|
||||
@ -93,28 +80,20 @@ def test_to_prepare_with_identifier_replaces
|
||||
Dispatcher.to_prepare(:unique_id) { |*args| a = b = 1 }
|
||||
Dispatcher.to_prepare(:unique_id) { |*args| a = 2 }
|
||||
|
||||
@dispatcher.unprepared = true
|
||||
@dispatcher.send! :prepare_application
|
||||
@dispatcher.send :run_callbacks, :prepare_dispatch
|
||||
assert_equal 2, a
|
||||
assert_equal nil, b
|
||||
end
|
||||
|
||||
def test_to_prepare_only_runs_once_if_not_loading_dependencies
|
||||
Dependencies.stubs(:load?).returns(false)
|
||||
called = 0
|
||||
Dispatcher.to_prepare(:unprepared_test) { |*args| called += 1 }
|
||||
2.times { dispatch }
|
||||
assert_equal 1, called
|
||||
end
|
||||
|
||||
private
|
||||
def dispatch(output = @output)
|
||||
def dispatch(output = @output, cache_classes = true)
|
||||
controller = mock
|
||||
controller.stubs(:process).returns(controller)
|
||||
controller.stubs(:out).with(output).returns('response')
|
||||
|
||||
ActionController::Routing::Routes.stubs(:recognize).returns(controller)
|
||||
|
||||
Dispatcher.define_dispatcher_callbacks(cache_classes)
|
||||
Dispatcher.dispatch(nil, {}, output)
|
||||
end
|
||||
|
||||
|
@ -24,7 +24,7 @@ def new_session
|
||||
def reload!
|
||||
puts "Reloading..."
|
||||
dispatcher = ActionController::Dispatcher.new($stdout)
|
||||
dispatcher.cleanup_application(true)
|
||||
dispatcher.prepare_application(true)
|
||||
dispatcher.cleanup_application
|
||||
dispatcher.reload_application
|
||||
true
|
||||
end
|
||||
|
@ -135,6 +135,9 @@ def process
|
||||
|
||||
load_application_initializers
|
||||
|
||||
# Prepare dispatcher callbacks and run 'prepare' callbacks
|
||||
prepare_dispatcher
|
||||
|
||||
# the framework is now fully initialized
|
||||
after_initialize
|
||||
|
||||
@ -442,6 +445,12 @@ def load_application_initializers
|
||||
end
|
||||
end
|
||||
|
||||
def prepare_dispatcher
|
||||
require 'dispatcher' unless defined?(::Dispatcher)
|
||||
Dispatcher.define_dispatcher_callbacks(configuration.cache_classes)
|
||||
Dispatcher.new(RAILS_DEFAULT_LOGGER).send :run_callbacks, :prepare_dispatch
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
# The Configuration class holds all the parameters for the Initializer and
|
||||
|
@ -13,17 +13,20 @@ class ApplicationController < ActionController::Base; end
|
||||
Test::Unit.run = false
|
||||
|
||||
class ConsoleAppTest < Test::Unit::TestCase
|
||||
def test_reload_should_fire_preparation_callbacks
|
||||
a = b = c = nil
|
||||
uses_mocha 'console reload test' do
|
||||
def test_reload_should_fire_preparation_callbacks
|
||||
a = b = c = nil
|
||||
|
||||
Dispatcher.to_prepare { a = b = c = 1 }
|
||||
Dispatcher.to_prepare { b = c = 2 }
|
||||
Dispatcher.to_prepare { c = 3 }
|
||||
Dispatcher.to_prepare { a = b = c = 1 }
|
||||
Dispatcher.to_prepare { b = c = 2 }
|
||||
Dispatcher.to_prepare { c = 3 }
|
||||
ActionController::Routing::Routes.expects(:reload)
|
||||
|
||||
reload!
|
||||
reload!
|
||||
|
||||
assert_equal 1, a
|
||||
assert_equal 2, b
|
||||
assert_equal 3, c
|
||||
assert_equal 1, a
|
||||
assert_equal 2, b
|
||||
assert_equal 3, c
|
||||
end
|
||||
end
|
||||
end
|
||||
|
Loading…
Reference in New Issue
Block a user