-
Notifications
You must be signed in to change notification settings - Fork 21.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Disable ActionView::Template finalizers in test environment #32418
Disable ActionView::Template finalizers in test environment #32418
Conversation
Thanks for the pull request, and welcome! The Rails team is excited to review your changes, and you should hear from @eileencodes (or someone else) soon. If any changes to this PR are deemed necessary, please add them as extra commits. This ensures that the reviewer can see what has changed since they last reviewed the code. Due to the way GitHub handles out-of-date commits, this should also make it reasonably obvious what issues have or haven't been addressed. Large or tricky changes may require several passes of review and changes. This repository is being automatically checked for code quality issues using Code Climate. You can see results for this analysis in the PR status below. Newly introduced issues should be fixed before a Pull Request is considered ready to review. Please see the contribution instructions for more information. |
Can you add a changelog entry? |
d2ee896
to
9a46b89
Compare
Done! (Ack, sorry, just realised I squashed it onto the same commit despite rails-bot's advice; I'll push any further code changes separately.) |
It is good squashed. I was going to ask to squash anyway. Thanks. |
|
||
Template finalization can be expensive in large view test suites. | ||
Add a configuration option, | ||
`action_view.finalize_compiled_template_methods`, and turn it off in |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This reminder me that we need to update the configuration guide to add this new option. Can you do that?
b5f0cc5
to
2decfd4
Compare
Can you squash your commits now? |
Question - wouldn't this also slow down the exiting of an app in production? |
ActionView::Template instances compile their source to methods on the ActionView::CompiledTemplates module. To prevent leaks in development mode, where templates can frequently change, a finalizer is added that undefines these methods[1] when the templates are garbage-collected. This is undesirable in the test environment, however, as templates don't change during the life of the test. Moreover, the cost of undefining a method is proportional to the number of descendants a class or module has, since the method cache must be cleared for all descendant classes. As ActionView::CompiledTemplates is mixed into every ActionView::TestCase (or in RSpec suites, every view spec example group), it can end up with a very large number of descendants, and undefining its methods can become very expensive. In large test suites, this results in a long delay at the end of the test suite as all template finalizers are run, only for the process to then exit. To avoid this unnecessary cost, this change adds a config option, `action_view.finalize_compiled_template_methods`, defaulting to true, and sets it to false in the test environment only. [1] https://github.com/rails/rails/blob/09b2348f7fc8d4e7191e70e06608c5909067e2aa/actionview/lib/action_view/template.rb#L118-L126
2decfd4
to
eede8d8
Compare
@rafaelfranca squashed and rebased! @pixeltrix In theory, yes. However in practice, because very few application classes are descendants of [1] In most apps it'll just be |
…iled_template_methods` Since we introduced default option for `class_attribute` and `mattr_accessor` family of methods and changed all occurrences of setting default values by using of `:default` option I think it would be fine to use `:default` option in order to set default value of `finalize_compiled_template_methods` since it expresses itself very well. Related to rails#29294, rails#32418
…mplate_methods` Follow up of #32418.
Summary
To avoid expensive finalization of
ActionView::Template
instances at the end of large test suites, this adds a configuration option to disable the finalizers, and uses it to disable them in the test environment.Description
ActionView::Template instances compile their source to methods on the ActionView::CompiledTemplates module. To prevent leaks in development mode, where templates can frequently change, a finalizer is added that undefines these methods when the templates are garbage-collected.
This is undesirable in the test environment, however, as templates don't change during the life of the test, so there's no leak to be avoided. Moreover, the cost of undefining a method is proportional to the number of descendants a class or module has, since the method cache must be cleared for all descendant classes.
As
ActionView::CompiledTemplates
is mixed intoActionView::TestCase
(or in RSpec suites, every view example group), it can end up with a very large number of descendants, and undefining its methods can become very expensive. In large test suites, this results in a long delay at the end of the test suite as all template finalizers are run, only for the process to then exit.To avoid this unnecessary cost, this change adds a config option,
action_view.finalize_compiled_template_methods
, defaulting to true, and sets it to false in the test environment only.Other Information
I've built a small reproduction of this issue using RSpec, illustrating a test suite that has 1,000 templates. For this suite the finalization cost at the end of the run is approximately 30 seconds, which is comparable to the delay seen in the app I'm currently working on (~45s).
Feedback
I've confirmed that this patch addresses the performance issue. However, I'm not entirely sure that exposing a configuration option is the best thing in this instance, since it's inevitably a rather obscure flag that the vast majority of users probably won't want to touch.
Any and all feedback is obviously welcome, but in particular if anyone has a better idea for making this environment-specific change, I'd be very open to suggestions.