developmentを実現したいのでコードを読んでみる#5
昨日ログを出力するように変更したrailsを使って、ほとんど素のrails3のアプリでサーバの起動、GETリクエストx3、サーバの停止までにActionDispatch::Reloaderの各メソッドがどのように呼びだされるのか、developmentとproductionの場合それぞれについて出力してみました。
https://github.com/akm/rails3_reloader_study/blob/master/actiondispatch_reloader_method_invocations_development.log
https://github.com/akm/rails3_reloader_study/blob/master/actiondispatch_reloader_method_invocations_production.log
production
起動時
ActionDispatch::Reloader.to_cleanup(
module Rails class Application module Bootstrap include Initializable # (中略) initializer :set_clear_dependencies_hook, :group => :all do ActionDispatch::Reloader.to_cleanup do ActiveSupport::DescendantsTracker.clear ActiveSupport::Dependencies.clear end end
ActionDispatch::Reloader.to_prepare(
module I18n class Railtie < Rails::Railtie # (中略) initializer "i18n.callbacks" do ActionDispatch::Reloader.to_prepare do I18n::Railtie.reloader.execute_if_updated end end
ActionDispatch::Reloader.prepare!
ActionDispatch::Reloader#initialize(nil)
module Rails class Application module Finisher include Initializable # (中略) initializer :run_prepare_callbacks do ActionDispatch::Reloader.prepare! end
module ActionDispatch class Reloader include ActiveSupport::Callbacks # (中略) # Execute all prepare callbacks. def self.prepare! self.trace_log(:prepare!) new(nil).run_callbacks :prepare end
GET /tests/foo?idx=1
ActionDispatch::Reloader.to_prepare(
module Rails class Application module Finisher include Initializable # (中略) initializer :set_routes_reloader do |app| reloader = lambda { app.routes_reloader.execute_if_updated } reloader.call ActionDispatch::Reloader.to_prepare(&reloader) end
ActionDispatch::Reloader.to_cleanup(
ActionDispatch::Reloader.to_prepare(
module ActiveRecord # = Active Record Railtie class Railtie < Rails::Railtie # (中略) initializer "active_record.set_dispatch_hooks", :before => :set_clear_dependencies_hook do |app| ActiveSupport.on_load(:active_record) do ActionDispatch::Reloader.to_cleanup do ActiveRecord::Base.clear_reloadable_connections! ActiveRecord::Base.clear_cache! end end end config.after_initialize do ActiveSupport.on_load(:active_record) do instantiate_observers ActionDispatch::Reloader.to_prepare do ActiveRecord::Base.instantiate_observers end end end
GET /tests/foo?idx=2
なし
GET /tests/foo?idx=3
なし
サーバを停止
なし
まとめ
development
起動時
ActionDispatch::Reloader.to_cleanup(
ActionDispatch::Reloader.to_prepare(
これらはproductionと同じ。
ActionDispatch::Reloader#initialize(#
/Users/akima/workspace/rails/actionpack/lib/action_dispatch/middleware/stack.rb:112:in `build' /Users/akima/workspace/rails/railties/lib/rails/engine.rb:447:in `app'
module ActionDispatch class MiddlewareStack # (中略) def build(app = nil, &block) app ||= block raise "MiddlewareStack#build requires an app" unless app middlewares.reverse.inject(app) { |a, e| e.build(a) } end
module Rails class Engine < Railtie # (中略) def app @app ||= begin config.middleware = config.middleware.merge_into(default_middleware_stack) config.middleware.build(endpoint) end end
GET /tests/foo?idx=1
ActionDispatch::Reloader.prepare!
ActionDispatch::Reloader#initialize(nil)
これらはproductionの起動時に実行されるものと同じ
ActionDispatch::Reloader.to_prepare(
productionのGET /tests/foo?idx=1で実行されるものと同じ
ActionDispatch::Reloader#call({"GATEWAY_INTERFACE"=>"CGI/1.1", "PATH_INFO"=>"/tests/foo", "QUERY_STRING"=>"idx=1", ...)
module Rack class Sendfile # (中略) def call(env) status, headers, body = @app.call(env) if body.respond_to?(:to_path) case type = variation(env)
ActionDispatch::Reloader.to_cleanup(
ActionDispatch::Reloader.to_prepare(
productionのGET /tests/foo?idx=1で実行されるものと同じ
ActiveRecord::ConnectionAdapters::ConnectionManagement::Proxy#close
ActionDispatch::Reloader.cleanup!
ActionDispatch::Reloader#initialize(nil)
module Rack module Handler def service(req, res) # (中略) status, headers, body = @app.call(env) begin res.status = status.to_i headers.each { |k, vs| if k.downcase == "set-cookie" res.cookies.concat vs.split("\n") else # Since WEBrick won't accept repeated headers, # merge the values per RFC 1945 section 4.2. res[k] = vs.split("\n").join(", ") end } body.each { |part| res.body << part } ensure body.close if body.respond_to? :close end end
module ActionDispatch class Reloader # (中略) # Execute all cleanup callbacks. def self.cleanup! self.trace_log(:cleanup!) new(nil).run_callbacks :cleanup end # (中略) module CleanupOnClose def close ActionDispatch::Reloader.trace_log_impl("#{self.class.name}#close") super if defined?(super) ensure ActionDispatch::Reloader.cleanup! end end
GET /tests/foo?idx=2
ActionDispatch::Reloader#call({"GATEWAY_INTERFACE"=>"CGI/1.1", "PATH_INFO"=>"/tests/foo", "QUERY_STRING"=>"idx=2", ...)
GET /tests/foo?idx=3
ActiveRecord::ConnectionAdapters::ConnectionManagement::Proxy#close
ActionDispatch::Reloader.cleanup!
ActionDispatch::Reloader#initialize(nil)
ActionDispatch::Reloader#call({"GATEWAY_INTERFACE"=>"CGI/1.1", "PATH_INFO"=>"/tests/foo", "QUERY_STRING"=>"idx=3", ...)
サーバを停止
ActiveRecord::ConnectionAdapters::ConnectionManagement::Proxy#close
ActionDispatch::Reloader.cleanup!
ActionDispatch::Reloader#initialize(nil)