aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKir Shatrov <shatrov@me.com>2017-06-24 10:57:36 -0400
committerKir Shatrov <shatrov@me.com>2017-07-29 14:03:52 +0300
commit0668c22a41e4c88ccb7600fc5b4bfb1a5b76e45d (patch)
tree83ab792d98f40879901860712248559a8a1ebc27
parent904f1a8747958129124d86b44e36c5f0263e0125 (diff)
downloadrails-0668c22a41e4c88ccb7600fc5b4bfb1a5b76e45d.tar.gz
rails-0668c22a41e4c88ccb7600fc5b4bfb1a5b76e45d.tar.bz2
rails-0668c22a41e4c88ccb7600fc5b4bfb1a5b76e45d.zip
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] https://github.com/rails/rails/blob/a3813dce9a0c950a4af7909111fa730a2622b1db/actionpack/lib/abstract_controller/base.rb#L66-L77
-rw-r--r--actionmailer/lib/action_mailer/railtie.rb6
-rw-r--r--actionpack/lib/action_controller/railtie.rb6
-rw-r--r--railties/test/application/configuration_test.rb60
3 files changed, 72 insertions, 0 deletions
diff --git a/actionmailer/lib/action_mailer/railtie.rb b/actionmailer/lib/action_mailer/railtie.rb
index 36c2e5866d..69578471b0 100644
--- a/actionmailer/lib/action_mailer/railtie.rb
+++ b/actionmailer/lib/action_mailer/railtie.rb
@@ -58,6 +58,12 @@ module ActionMailer
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|
options = app.config.action_mailer
diff --git a/actionpack/lib/action_controller/railtie.rb b/actionpack/lib/action_controller/railtie.rb
index 1c1cd58732..0d7a230b17 100644
--- a/actionpack/lib/action_controller/railtie.rb
+++ b/actionpack/lib/action_controller/railtie.rb
@@ -77,5 +77,11 @@ module ActionController
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
diff --git a/railties/test/application/configuration_test.rb b/railties/test/application/configuration_test.rb
index 9f62ca8eb8..aa5a1b09fd 100644
--- a/railties/test/application/configuration_test.rb
+++ b/railties/test/application/configuration_test.rb
@@ -238,6 +238,66 @@ module ApplicationTests
assert_instance_of Pathname, Rails.public_path
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
add_to_config <<-RUBY
config.eager_load = true