1
0
Fork 0
mirror of https://github.com/rails/rails.git synced 2022-11-09 12:12:34 -05:00

Eager load controller and mailer actions

On the first request, ActionController::Base#action_methods computes
and memoized the list of available actions [1]. With this PR we move
this expensive operation into eager load step to reduce response time
of the first request served in production.

This also reduces the memory footprint when running on forking server
like Unicorn.

[1] a3813dce9a/actionpack/lib/abstract_controller/base.rb (L66-L77)
This commit is contained in:
Kir Shatrov 2017-06-24 10:57:36 -04:00
parent 904f1a8747
commit 0668c22a41
3 changed files with 72 additions and 0 deletions

View file

@ -58,6 +58,12 @@ module ActionMailer
end end
end end
initializer "action_mailer.eager_load_actions" do
ActiveSupport.on_load(:after_initialize) do
ActionMailer::Base.descendants.each(&:action_methods) if config.eager_load
end
end
config.after_initialize do |app| config.after_initialize do |app|
options = app.config.action_mailer options = app.config.action_mailer

View file

@ -77,5 +77,11 @@ module ActionController
end end
end end
end end
initializer "action_controller.eager_load_actions" do
ActiveSupport.on_load(:after_initialize) do
ActionController::Metal.descendants.each(&:action_methods) if config.eager_load
end
end
end end
end end

View file

@ -238,6 +238,66 @@ module ApplicationTests
assert_instance_of Pathname, Rails.public_path assert_instance_of Pathname, Rails.public_path
end end
test "does not eager load controller actions in development" do
app_file "app/controllers/posts_controller.rb", <<-RUBY
class PostsController < ActionController::Base
def index;end
def show;end
end
RUBY
app "development"
assert_nil PostsController.instance_variable_get(:@action_methods)
end
test "eager loads controller actions in production" do
app_file "app/controllers/posts_controller.rb", <<-RUBY
class PostsController < ActionController::Base
def index;end
def show;end
end
RUBY
add_to_config <<-RUBY
config.eager_load = true
config.cache_classes = true
RUBY
app "production"
assert_equal %w(index show).to_set, PostsController.instance_variable_get(:@action_methods)
end
test "does not eager load mailer actions in development" do
app_file "app/mailers/posts_mailer.rb", <<-RUBY
class PostsMailer < ActionMailer::Base
def noop_email;end
end
RUBY
app "development"
assert_nil PostsMailer.instance_variable_get(:@action_methods)
end
test "eager loads mailer actions in production" do
app_file "app/mailers/posts_mailer.rb", <<-RUBY
class PostsMailer < ActionMailer::Base
def noop_email;end
end
RUBY
add_to_config <<-RUBY
config.eager_load = true
config.cache_classes = true
RUBY
app "production"
assert_equal %w(noop_email).to_set, PostsMailer.instance_variable_get(:@action_methods)
end
test "initialize an eager loaded, cache classes app" do test "initialize an eager loaded, cache classes app" do
add_to_config <<-RUBY add_to_config <<-RUBY
config.eager_load = true config.eager_load = true