Skip to content

Ensure application gets reloaded only once#5740

Merged
javierjulio merged 2 commits intoactiveadmin:masterfrom
waysact:5739-reload-once
Apr 25, 2019
Merged

Ensure application gets reloaded only once#5740
javierjulio merged 2 commits intoactiveadmin:masterfrom
waysact:5739-reload-once

Conversation

@jscheid
Copy link
Contributor

@jscheid jscheid commented Apr 13, 2019

I've recently used ruby-prof to look at reload performance, like so:

require 'ruby-prof'

result = RubyProf.profile do
  Rails.application.reloader.reload!
end
printer = RubyProf::MultiPrinter.new(result)
printer.print(path: "/path/to/output", profile: "reload-profile")

Doing so revealed that ActiveAdmin.application.load! is called twice. Since that method accounts for a substantial portion of the time it takes to reload our app, this seems quite wasteful.

The reason is that the prepare callback is invoked twice, from here:

https://github.com/rails/rails/blob/v5.2.3/activesupport/lib/active_support/reloader.rb#L46

and from here:

https://github.com/rails/rails/blob/v5.2.3/activesupport/lib/active_support/reloader.rb#L59

For the "load" callback alone this wouldn't be a problem because it only calls load! if the application is not already loaded. However, the "unload" callback also uses the prepare callback, which results in the following order of callbacks:

  1. unload
  2. load
  3. unload
  4. load

That defeats the loaded? guard because by the time the "load" callback is invoked a second time, the application has been unloaded again.

This PR attempts to solve the problem by using the class_unload event instead of the prepare event for the "unload" callback. That event is only invoked once per reload.

It also removes the compatibility layer in reloader.rb. As far as I can tell, it is no longer needed now that support for Rails 4.x has been dropped.

It also simplifies the logic for registering the "unload" callback because the same callback works regardless of the setting for reload_classes_only_on_change.

Closes #5739

@deivid-rodriguez
Copy link
Member

I love this ❤️.

One thought and two nitpicks.

Maybe we should land the #5732 PR first, in case this conflicts with Zeitwerk. In particular, I think the spec you have added will need to run with the CLASS_RELOADING environment variable set (which configures Rails cache_classes on our test app), because Zeitwerk explicitly forbids reloading unless that setting is enabled.

As nitpicks, I'd love if you could split the PR into two separate commits, one that removes the unnecessary compatibility layer with the Rails reloader, and another one that fixes the double loading issue.

The other one is that the "integration_spec.rb" file we could maybe be renamed to "rails_integration_spec.rb"

@jscheid
Copy link
Contributor Author

jscheid commented Apr 13, 2019

Sure, no problem. I’ll get to it tomorrow or Monday.

@jscheid
Copy link
Contributor Author

jscheid commented Apr 13, 2019

@deivid-rodriguez all done. I've also merged your zeitgeist branch into my local to see how the two work together. The test seems to pass fine without CLASS_RELOADING set. Perhaps because no code has changed before the reload is triggered?

(And yes I've run the specs with export BUNDLE_GEMFILE=gemfiles/rails_60.gemfile 😺)

varyonic added a commit to activeadmin-rails/activeadmin-rails that referenced this pull request Apr 19, 2019
* 5739-reload-once:
  Ensure application gets reloaded only once
  Remove reloader compatibility layer
@deivid-rodriguez
Copy link
Member

This looks good to me! Thanks @jscheid!

Just in case, can you rebase this since there's been a few changes in zeitwerk and rails since last time?

@deivid-rodriguez
Copy link
Member

Oh, can you also add a changelog entry for the reloading fix?

@jscheid
Copy link
Contributor Author

jscheid commented Apr 25, 2019

@deivid-rodriguez rebased... could you add the change log please? I don't know what version it will be released in.

@deivid-rodriguez
Copy link
Member

You don't need to know it, put it under the "Unreleased" section. Anyways, I can do it, no problem 😃

@jscheid
Copy link
Contributor Author

jscheid commented Apr 25, 2019

Ah, now it did break. Good call. Curious, because it definitely didn't the other day (with Zeitwerk merged in). I'll have another look at this tomorrow 😕

@deivid-rodriguez
Copy link
Member

Great, thanks!

@deivid-rodriguez
Copy link
Member

I plan to release this with 2.1 by the way, together with "official" Rails 6 support.

This is no longer needed now that support for Rails 4.x has been
dropped.
@jscheid
Copy link
Contributor Author

jscheid commented Apr 25, 2019

@deivid-rodriguez any idea what the codeclimate failure is about? I'm inclined to think it's a bug... I had pushed the same change before with the only difference in the change log, and it didn't complain.

@jscheid
Copy link
Contributor Author

jscheid commented Apr 25, 2019

Oh, maybe it didn't run because of the conflict... anyway, do you know off the top of your head how this can be resolved? Never mind, it wasn't running the new spec type in CI.

@deivid-rodriguez
Copy link
Member

deivid-rodriguez commented Apr 25, 2019

Since you're adding a new "suite", you need to make sure coverage reports are properly merged together. You should create a new spec/support/simplecov_reload_env.rb file doing something similar to spec/support/simplecov_regular_env.rb and spec/support/simplecov_changes_env.rb.

@jscheid
Copy link
Contributor Author

jscheid commented Apr 25, 2019

@deivid-rodriguez there are already cucumber specs for this type. Were they not considered for code coverage before?

@deivid-rodriguez
Copy link
Member

Cucumber reloading specs are also part of a separate suite, which is properly configured for coverage report merging. Basically every set of specs/features that run as a separate process needs custom code so that their coverage reports are properly merged.

@jscheid
Copy link
Contributor Author

jscheid commented Apr 25, 2019

Ah, I think we're good: https://github.com/activeadmin/activeadmin/blob/master/features/support/simplecov_reload_env.rb

I think problem was just that the new type didn't run in CI. 🤞

@jscheid
Copy link
Contributor Author

jscheid commented Apr 25, 2019

You were right, that file was missing.

What a drag... you're lucky you got your PR in before mine 😉

Should be all good now?

Copy link
Member

@deivid-rodriguez deivid-rodriguez left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

❤️

Copy link
Member

@javierjulio javierjulio left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks great, thank you! 👏🏻

@javierjulio javierjulio merged commit 21e0f82 into activeadmin:master Apr 25, 2019
@jscheid
Copy link
Contributor Author

jscheid commented Apr 26, 2019

You're welcome, thanks for merging.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Reloads application twice

3 participants