avo
avo copied to clipboard
Presence of Avo forces full Zeitwerk app reload on any change
Describe the bug
Having Avo gem in your gemfile causes Zeitwerk to unload and reload every Class/Module on change to any Class/Module, rather than only those that are influenced. This causes, in my actual job application, ~10 second hang in development server on any change to a Ruby file.
Steps to Reproduce
Steps to reproduce the behavior:
rails new test_reloading --minimalrails g scaffold should_reloadrails g scaffold do_not_reloadrails db:create db:migrate- Add
Rails.autoloaders.log!to bottom ofapplication.rb - Run your server. Your server log should contain a block of lines similar to
[email protected]: autoload set for ApplicationController, to be loaded from... - visit
/should_reloads, you will see some Zeitwerk activity. - Reload the page, you will not see Zeitwerk activity.
- Make a change to
ShouldReloadController#index(tho any file would do honestly). The change does not matter, you could addone = 1. It's just the presence of a change. - Reload the page. Your output should include (not necessarily in this order):
[email protected]: autoload for DoNotReload removed <<< THIS IS THE SIGNIFICANT BIT
[email protected]: ShouldReload unloaded
[email protected]: autoload set for ShouldReload, to be loaded from /Blah/blah/blah
- Add Avo to gemfile &
bundle install - Uncomment
require "active_job/railtie"inapplication.rb(required by Avo) - Run steps 6 through 10, only step 10 server output should include (not necessarily in this order):
[email protected]: DoNotReload unloaded <<< THIS IS THE SIGNIFICANT BIT
[email protected]: ShouldReload unloaded
[email protected]: autoload set for DoNotreload, to be loaded from /Blah/blah/blah
[email protected]: autoload set for ShouldReload, to be loaded from /Blah/blah/blah
You would also experience a very long hang in a real application. Again, in my actual app this is ~10 seconds.
Expected behavior & Actual behavior
Expected: Any code unrelated to a change should have its Zeitwerk autoload removed prior to code unloading.
Actual: All application code is unloaded and reloaded.
System configuration
Avo version: 2.15.3
Rails version: 7.0.4
Ruby version: 3.1.2
License type:
- [ ] Community
- [X] Pro
Context
I lived with this problem longer than I should have, didn't take the time to figure out the origin early enough until today. This has slowed development, and really frustrated me, for several days.
I actually thought it might be some weird local environment thing so I straight up reimaged my computer yesterday. It's a fresh up to date MacOS 12.6 install with like, nothing except RubyMine and my app repo on it.
Unfortunately its only really impactful when using the development server, so it's easy to miss if you're TDD'n, which I have been, so I am not really sure when it first started being an issue. Now that I'm doing frontend work in view components, which of course are classes, it's completely debilitating.
Impact
- [X] High impact
- [ ] Medium impact
- [ ] Low impact
Urgency
- [X] High urgency
- [ ] Medium urgency
- [ ] low urgency
My workaround has been to have a NO_AVO environment variable that conditionally wraps all Avo everything so it just isn't loaded. This allows me to do frontend work.
Hey @dhnaranjo. First of all, apologies for the radio silence. I had other matters to attend to this past week. I didn't have any time for dev-work.
I did all the steps in the reproduction section and I see what you mean.
I'm trying to figure it out and see what is triggering that.
I figured out why this is happening. It's because of https://github.com/avo-hq/avo/blob/main/lib/avo/dynamic_router.rb#L4.
I'm triggering a Rails.application.eager_load! so I'll have access to BaseResource.descendants. It seems that Rails doesn't load up all those resources we declare in the app/avo/resources and they are not available in ObjectSpace.
@dhnaranjo do you have any experience with these things? The requirement here is to get all the BaseResource descendants so we can generate the routes.
I'm happy to remove the eager_load! statement if we can find another way of doing that.
descendants docs
I spent a while tryinna sort this out before I saw that thread. Learned some neat stuff, not much of it useful.
Thankfully the recommendation in https://github.com/fxn/zeitwerk/issues/232#issuecomment-1272270538 does work. I'm working on making it a bit prettier.
I think the best way to proceed with this is to apply some kind of monkey patch with the file-based solution you linked to and wait for zeitwerk's complete patch to bring it into Avo permanently. WDYT?
Please share your solution when you have applied something that works.
Aight here's this here: https://github.com/avo-hq/avo/pull/1297, but it doesn't actually fix the whole problem. Fewer objects are reloaded with the change, but I still think it's more than ought to. I'mma put together a lil test.
Hey @dhnaranjo, give 2.17.1.pre.1.zeitwerk.eager.load.dir a try and let me know if the issue persists.
Please add zeitwerk's master branch to your Gemfile.
# Gemfile
gem "avo", "2.17.1.pre.1.zeitwerk.eager.load.dir"
gem "zeitwerk", github: "fxn/zeitwerk"