Get rid of config.preload_frameworks in favor of config.eager_load_namespaces

The new option allows any Ruby namespace to be registered and set
up for eager load. We are effectively exposing the structure existing
in Rails since v3.0 for all developers in order to make their applications
thread-safe and CoW friendly.
This commit is contained in:
José Valim 2012-08-01 20:54:22 +02:00
parent a1687e48cb
commit 2801786e1a
23 changed files with 80 additions and 52 deletions

@ -35,7 +35,10 @@
module ActionMailer module ActionMailer
extend ::ActiveSupport::Autoload extend ::ActiveSupport::Autoload
autoload :Collector eager_autoload do
autoload :Collector
end
autoload :Base autoload :Base
autoload :DeliveryMethods autoload :DeliveryMethods
autoload :MailHelper autoload :MailHelper

@ -5,6 +5,7 @@
module ActionMailer module ActionMailer
class Railtie < Rails::Railtie class Railtie < Rails::Railtie
config.action_mailer = ActiveSupport::OrderedOptions.new config.action_mailer = ActiveSupport::OrderedOptions.new
config.eager_load_namespaces << ActionMailer
initializer "action_mailer.logger" do initializer "action_mailer.logger" do
ActiveSupport.on_load(:action_mailer) { self.logger ||= Rails.logger } ActiveSupport.on_load(:action_mailer) { self.logger ||= Rails.logger }

@ -48,6 +48,12 @@ module ActionController
eager_autoload do eager_autoload do
autoload :RecordIdentifier autoload :RecordIdentifier
end end
def self.eager_load!
super
ActionController::Caching.eager_load!
HTML.eager_load!
end
end end
# All of these simply register additional autoloads # All of these simply register additional autoloads

@ -9,6 +9,8 @@ module ActionController
class Railtie < Rails::Railtie #:nodoc: class Railtie < Rails::Railtie #:nodoc:
config.action_controller = ActiveSupport::OrderedOptions.new config.action_controller = ActiveSupport::OrderedOptions.new
config.eager_load_namespaces << ActionController
initializer "action_controller.assets_config", :group => :all do |app| initializer "action_controller.assets_config", :group => :all do |app|
app.config.action_controller.assets_dir ||= app.config.paths["public"].first app.config.action_controller.assets_dir ||= app.config.paths["public"].first
end end

@ -38,9 +38,11 @@ module ActionDispatch
class IllegalStateError < StandardError class IllegalStateError < StandardError
end end
autoload_under 'http' do eager_autoload do
autoload :Request autoload_under 'http' do
autoload :Response autoload :Request
autoload :Response
end
end end
autoload_under 'middleware' do autoload_under 'middleware' do

@ -25,6 +25,8 @@ class Railtie < Rails::Railtie
'X-Content-Type-Options' => 'nosniff' 'X-Content-Type-Options' => 'nosniff'
} }
config.eager_load_namespaces << ActionDispatch
initializer "action_dispatch.configure" do |app| initializer "action_dispatch.configure" do |app|
ActionDispatch::Http::URL.tld_length = app.config.action_dispatch.tld_length ActionDispatch::Http::URL.tld_length = app.config.action_dispatch.tld_length
ActionDispatch::Request.ignore_accept_header = app.config.action_dispatch.ignore_accept_header ActionDispatch::Request.ignore_accept_header = app.config.action_dispatch.ignore_accept_header

@ -38,7 +38,6 @@ module ActionView
autoload :PathSet autoload :PathSet
autoload :Template autoload :Template
autoload_under "renderer" do autoload_under "renderer" do
autoload :Renderer autoload :Renderer
autoload :AbstractRenderer autoload :AbstractRenderer
@ -77,6 +76,11 @@ module ActionView
autoload :TestCase autoload :TestCase
ENCODING_FLAG = '#.*coding[:=]\s*(\S+)[ \t]*' ENCODING_FLAG = '#.*coding[:=]\s*(\S+)[ \t]*'
def self.eager_load!
super
ActionView::Template.eager_load!
end
end end
require 'active_support/core_ext/string/output_safety' require 'active_support/core_ext/string/output_safety'

@ -9,6 +9,8 @@ class Railtie < Rails::Railtie
config.action_view.javascript_expansions = { :defaults => %w(jquery jquery_ujs) } config.action_view.javascript_expansions = { :defaults => %w(jquery jquery_ujs) }
config.action_view.embed_authenticity_token_in_remote_forms = false config.action_view.embed_authenticity_token_in_remote_forms = false
config.eager_load_namespaces << ActionView
initializer "action_view.embed_authenticity_token_in_remote_forms" do |app| initializer "action_view.embed_authenticity_token_in_remote_forms" do |app|
ActiveSupport.on_load(:action_view) do ActiveSupport.on_load(:action_view) do
ActionView::Helpers::FormTagHelper.embed_authenticity_token_in_remote_forms = ActionView::Helpers::FormTagHelper.embed_authenticity_token_in_remote_forms =

@ -34,7 +34,6 @@ module ActiveModel
autoload :Conversion autoload :Conversion
autoload :Dirty autoload :Dirty
autoload :EachValidator, 'active_model/validator' autoload :EachValidator, 'active_model/validator'
autoload :Errors
autoload :Lint autoload :Lint
autoload :MassAssignmentSecurity autoload :MassAssignmentSecurity
autoload :Model autoload :Model
@ -49,11 +48,22 @@ module ActiveModel
autoload :Validations autoload :Validations
autoload :Validator autoload :Validator
eager_autoload do
autoload :Errors
end
module Serializers module Serializers
extend ActiveSupport::Autoload extend ActiveSupport::Autoload
autoload :JSON eager_autoload do
autoload :Xml autoload :JSON
autoload :Xml
end
end
def eager_load!
super
ActiveModel::Serializer.eager_load!
end end
end end

@ -1,2 +1,8 @@
require "active_model" require "active_model"
require "rails" require "rails"
module ActiveModel
class Railtie < Rails::Railtie
config.eager_load_namespaces << ActiveModel
end
end

@ -160,6 +160,15 @@ module Tasks
autoload :TestCase autoload :TestCase
autoload :TestFixtures, 'active_record/fixtures' autoload :TestFixtures, 'active_record/fixtures'
def self.eager_load!
super
ActiveRecord::Locking.eager_load!
ActiveRecord::Scoping.eager_load!
ActiveRecord::Associations.eager_load!
ActiveRecord::AttributeMethods.eager_load!
ActiveRecord::ConnectionAdapters.eager_load!
end
end end
ActiveSupport.on_load(:active_record) do ActiveSupport.on_load(:active_record) do

@ -29,8 +29,11 @@ class Railtie < Rails::Railtie
'ActiveRecord::RecordNotSaved' => :unprocessable_entity 'ActiveRecord::RecordNotSaved' => :unprocessable_entity
) )
config.active_record.use_schema_cache_dump = true config.active_record.use_schema_cache_dump = true
config.eager_load_namespaces << ActiveRecord
rake_tasks do rake_tasks do
require "active_record/base" require "active_record/base"
load "active_record/railties/databases.rake" load "active_record/railties/databases.rake"

@ -5,6 +5,8 @@ module ActiveSupport
class Railtie < Rails::Railtie class Railtie < Rails::Railtie
config.active_support = ActiveSupport::OrderedOptions.new config.active_support = ActiveSupport::OrderedOptions.new
config.eager_load_namespaces << ActiveSupport
initializer "active_support.deprecation_behavior" do |app| initializer "active_support.deprecation_behavior" do |app|
if deprecation = app.config.active_support.deprecation if deprecation = app.config.active_support.deprecation
ActiveSupport::Deprecation.behavior = deprecation ActiveSupport::Deprecation.behavior = deprecation

@ -107,8 +107,6 @@ end
* +config.middleware+ allows you to configure the application's middleware. This is covered in depth in the "Configuring Middleware":#configuring-middleware section below. * +config.middleware+ allows you to configure the application's middleware. This is covered in depth in the "Configuring Middleware":#configuring-middleware section below.
* +config.preload_frameworks+ enables or disables preloading all frameworks at startup. Enabled by +config.threadsafe!+. Defaults to +nil+, so is disabled.
* +config.queue+ configures a different queue implementation for the application. Defaults to +Rails::Queueing::Queue+. Note that, if the default queue is changed, the default +queue_consumer+ is not going to be initialized, it is up to the new queue implementation to handle starting and shutting down its own consumer(s). * +config.queue+ configures a different queue implementation for the application. Defaults to +Rails::Queueing::Queue+. Note that, if the default queue is changed, the default +queue_consumer+ is not going to be initialized, it is up to the new queue implementation to handle starting and shutting down its own consumer(s).
* +config.queue_consumer+ configures a different consumer implementation for the default queue. Defaults to +Rails::Queueing::ThreadedConsumer+. * +config.queue_consumer+ configures a different consumer implementation for the default queue. Defaults to +Rails::Queueing::ThreadedConsumer+.
@ -127,7 +125,7 @@ config.session_store :my_custom_store
This custom store must be defined as +ActionDispatch::Session::MyCustomStore+. In addition to symbols, they can also be objects implementing a certain API, like +ActiveRecord::SessionStore+, in which case no special namespace is required. This custom store must be defined as +ActionDispatch::Session::MyCustomStore+. In addition to symbols, they can also be objects implementing a certain API, like +ActiveRecord::SessionStore+, in which case no special namespace is required.
* +config.threadsafe!+ enables +cache_classes+, +dependency_loading+, +eager_load+ and +preload_frameworks+ to make the application threadsafe. * +config.threadsafe!+ enables +cache_classes+ and +eager_load+ to make the application threadsafe.
WARNING: Threadsafe operation is incompatible with the normal workings of development mode Rails. In particular, automatic dependency loading and class reloading are automatically disabled when you call +config.threadsafe!+. WARNING: Threadsafe operation is incompatible with the normal workings of development mode Rails. In particular, automatic dependency loading and class reloading are automatically disabled when you call +config.threadsafe!+.
@ -654,8 +652,6 @@ Serves as a placeholder so that +:load_environment_config+ can be defined to run
*+load_active_support+* Requires +active_support/dependencies+ which sets up the basis for Active Support. Optionally requires +active_support/all+ if +config.active_support.bare+ is un-truthful, which is the default. *+load_active_support+* Requires +active_support/dependencies+ which sets up the basis for Active Support. Optionally requires +active_support/all+ if +config.active_support.bare+ is un-truthful, which is the default.
*+preload_frameworks+* Loads all autoload dependencies of Rails automatically if +config.preload_frameworks+ is +true+ or "truthful". By default this configuration option is disabled. In Rails, when internal classes are referenced for the first time they are autoloaded. +:preload_frameworks+ loads all of this at once on initialization.
*+initialize_logger+* Initializes the logger (an +ActiveSupport::BufferedLogger+ object) for the application and makes it accessible at +Rails.logger+, provided that no initializer inserted before this point has defined +Rails.logger+. *+initialize_logger+* Initializes the logger (an +ActiveSupport::BufferedLogger+ object) for the application and makes it accessible at +Rails.logger+, provided that no initializer inserted before this point has defined +Rails.logger+.
*+initialize_cache+* If +Rails.cache+ isn't set yet, initializes the cache by referencing the value in +config.cache_store+ and stores the outcome as +Rails.cache+. If this object responds to the +middleware+ method, its middleware is inserted before +Rack::Runtime+ in the middleware stack. *+initialize_cache+* If +Rails.cache+ isn't set yet, initializes the cache by referencing the value in +config.cache_store+ and stores the outcome as +Rails.cache+. If this object responds to the +middleware+ method, its middleware is inserted before +Rack::Runtime+ in the middleware stack.

@ -83,13 +83,6 @@ def initialize
@queue = nil @queue = nil
end end
# Eager load all dependencies before eager loading
# the application.
def eager_load!
railties.each(&:eager_load!)
super
end
# Returns true if the application is initialized. # Returns true if the application is initialized.
def initialized? def initialized?
@initialized @initialized

@ -16,7 +16,7 @@ module Bootstrap
initializer :set_eager_load, :group => :all do initializer :set_eager_load, :group => :all do
if config.eager_load.nil? if config.eager_load.nil?
warn <<-INFO warn <<-INFO
config.eager_load is set to nil. Please update your config/environments file accordingly: config.eager_load is set to nil. Please update your config/environments/*.rb files accordingly:
* development - set it to false * development - set it to false
* test - set it to false (unless you use a tool that preloads your test environment) * test - set it to false (unless you use a tool that preloads your test environment)
@ -27,13 +27,6 @@ module Bootstrap
end end
end end
# Preload all frameworks specified by the Configuration#frameworks.
# Used by Passenger to ensure everything's loaded before forking and
# to avoid autoload race conditions in JRuby.
initializer :preload_frameworks, :group => :all do
ActiveSupport::Autoload.eager_autoload! if config.preload_frameworks
end
# Initialize the logger early in the stack in case we need to log some deprecation. # Initialize the logger early in the stack in case we need to log some deprecation.
initializer :initialize_logger, :group => :all do initializer :initialize_logger, :group => :all do
Rails.logger ||= config.logger || begin Rails.logger ||= config.logger || begin

@ -9,7 +9,7 @@ class Configuration < ::Rails::Engine::Configuration
:cache_classes, :cache_store, :consider_all_requests_local, :console, :cache_classes, :cache_store, :consider_all_requests_local, :console,
:eager_load, :exceptions_app, :file_watcher, :filter_parameters, :eager_load, :exceptions_app, :file_watcher, :filter_parameters,
:force_ssl, :helpers_paths, :logger, :log_formatter, :log_tags, :force_ssl, :helpers_paths, :logger, :log_formatter, :log_tags,
:preload_frameworks, :railties_order, :relative_url_root, :secret_token, :railties_order, :relative_url_root, :secret_token,
:serve_static_assets, :ssl_options, :static_cache_control, :session_options, :serve_static_assets, :ssl_options, :static_cache_control, :session_options,
:time_zone, :reload_classes_only_on_change, :time_zone, :reload_classes_only_on_change,
:queue, :queue_consumer :queue, :queue_consumer
@ -95,7 +95,6 @@ def paths
# after boot, and disables reloading code on every request, as these are # after boot, and disables reloading code on every request, as these are
# fundamentally incompatible with thread safety. # fundamentally incompatible with thread safety.
def threadsafe! def threadsafe!
@preload_frameworks = true
@cache_classes = true @cache_classes = true
@eager_load = true @eager_load = true
self self

@ -52,7 +52,7 @@ module Finisher
initializer :eager_load! do initializer :eager_load! do
if config.eager_load if config.eager_load
ActiveSupport.run_load_hooks(:before_eager_load, self) ActiveSupport.run_load_hooks(:before_eager_load, self)
eager_load! config.eager_load_namespaces.each(&:eager_load!)
end end
end end

@ -339,11 +339,16 @@ class Engine < Railtie
class << self class << self
attr_accessor :called_from, :isolated attr_accessor :called_from, :isolated
alias :isolated? :isolated alias :isolated? :isolated
alias :engine_name :railtie_name alias :engine_name :railtie_name
delegate :eager_load!, to: :instance
def inherited(base) def inherited(base)
unless base.abstract_railtie? unless base.abstract_railtie?
Rails::Railtie::Configuration.eager_load_namespaces << base
base.called_from = begin base.called_from = begin
# Remove the line number from backtraces making sure we don't leave anything behind # Remove the line number from backtraces making sure we don't leave anything behind
call_stack = caller.map { |p| p.sub(/:\d+.*/, '') } call_stack = caller.map { |p| p.sub(/:\d+.*/, '') }

@ -178,9 +178,6 @@ def config
@config ||= Railtie::Configuration.new @config ||= Railtie::Configuration.new
end end
def eager_load!
end
def railtie_namespace def railtie_namespace
@railtie_namespace ||= self.class.parents.detect { |n| n.respond_to?(:railtie_namespace) } @railtie_namespace ||= self.class.parents.detect { |n| n.respond_to?(:railtie_namespace) }
end end

@ -7,6 +7,16 @@ def initialize
@@options ||= {} @@options ||= {}
end end
# Expose the eager_load_namespaces at "module" level for convenience.
def self.eager_load_namespaces #:nodoc:
@@eager_load_namespaces ||= []
end
# All namespaces that are eager loaded
def eager_load_namespaces
@@eager_load_namespaces ||= []
end
# Add files that should be watched for change. # Add files that should be watched for change.
def watchable_files def watchable_files
@@watchable_files ||= [] @@watchable_files ||= []

@ -176,22 +176,6 @@ def teardown
end end
end end
test "frameworks are not preloaded by default" do
require "#{app_path}/config/environment"
assert ActionController.autoload?(:Caching)
end
test "frameworks are preloaded with config.preload_frameworks is set" do
add_to_config <<-RUBY
config.preload_frameworks = true
RUBY
require "#{app_path}/config/environment"
assert !ActionView.autoload?(:AssetPaths)
end
test "filter_parameters should be able to set via config.filter_parameters" do test "filter_parameters should be able to set via config.filter_parameters" do
add_to_config <<-RUBY add_to_config <<-RUBY
config.filter_parameters += [ :foo, 'bar', lambda { |key, value| config.filter_parameters += [ :foo, 'bar', lambda { |key, value|

@ -75,7 +75,6 @@ def world
RUBY RUBY
output = Dir.chdir(app_path){ `rake do_nothing` } output = Dir.chdir(app_path){ `rake do_nothing` }
puts output
assert_match "Hello world", output assert_match "Hello world", output
end end