-
Notifications
You must be signed in to change notification settings - Fork 110
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
Find load_paths
dynamically by asking Rails and eliminate cache in Packwerk::Configuration
#150
Find load_paths
dynamically by asking Rails and eliminate cache in Packwerk::Configuration
#150
Conversation
"Extraneous load paths in file:\n#{format_yaml_strings(actual - expected)}" | ||
) | ||
end | ||
def validate_rails_app! |
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.
I decided to have the API to this here even though the implementation is in configuration (and the error is raised in the application load paths class), since it is a validator after all. Happy to incorporate any feedback here.
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.
I think we're talking about three responsibilities here:
- making sure we have a Rails app
- booting the Rails app
- extracting load paths
ApplicationLoadPaths
currently does all of that. It might make sense to move 1
and 2
into a separate class HostApplication
, to be reused here? Or have a differently named class that does it all - but I think the load path extraction logic is actually interesting enough to deserve its own class.
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.
I think we may not need to boot the application for validate
anymore once we have removed the two application state caches, so it might actually make sense to not extract the load paths here.
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.
Looking at this again, I think this comment still applies.
Do we actually need to validate it's a rails app here? If we don't packwerk check
might fail, but it would fail with a pretty obvious error message.
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.
No I suppose we don't -- I removed it on the second commit
4567bca
to
088aff0
Compare
lib/packwerk/configuration.rb
Outdated
@inflections_file = File.expand_path(configs["inflections_file"] || "config/inflections.yml", @root_path) | ||
@parallel = configs.key?("parallel") ? configs["parallel"] : true | ||
|
||
@config_path = config_path | ||
end | ||
|
||
def load_paths | ||
@load_paths ||= ApplicationLoadPaths.extract_relevant_paths(@root_path, 'test') |
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.
hard coded environment?
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.
I did this because the CLI by default hard-codes the environment with this value:
https://github.com/Shopify/packwerk/blob/main/lib/packwerk/cli.rb#L22
As far as I know it's not a feature to allow this val to be changed, so I kept it the same. Let me know what you think the best path forward is.
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.
mmh, yeah it's a good question which class should know about this. Intuitively, if we hard code this, it makes more sense for ApplicationLoadPaths
to know the value then for Configuration
, IMO.
OK, nitpicks and details aside - as I said on slack, I think this generally makes sense. However, I think we're not on the same page regarding spring, and we should also consider inflections. Let's start with the latter. Packwerk is currently effectively caching load paths and inflections to avoid booting the application for On the topic of spring, we brought this up because now, with you proposed change, the application needs to be booted in order to run When you're writing the code to boot the application, you should be able to do so using spring. The speed up we are looking for should be implicitly provided because spring won't start the application twice. |
I hope I remember correctly how spring works, will try to find the PR where Rafael removed it (and the binstubs) |
this is the PR I'm referring to #128, still reading it |
OK I need to dive a bit deeper into this, I lost track of where the application is actually booted in the latest release |
Happy to do that. Do you think that should be in this same PR or is having it be in a follow-up one okay? My understanding is that the
I may be misunderstanding here! My understanding is that Simply by accessing Regarding spring -- I'm not totally clear how spring works here, but I thought that spring basically wraps other commands and intercepts invocations to load the rails application and loads its own cache. Do I need to explicitly load something with Spring instead? If so, is there a way to make that work for users who don't use spring (perhaps the user can inject a dependency here for faster loading?)? |
Thank you for helping me along, yes, This part of the PR I mentioned shows how we were previously using spring to boot the application (need to expand You can see there's a fallback for if spring isn't available. |
That PR also has a little gem of info on the environment used to extract the autoload paths:
|
Inflections could go into a separate PR, and that would make things easier to digest. However, I do think of both modifications as one change to the product. The idea should be to eliminate all forms of caches for application configuration. |
Thanks for all the info. So if I'm understanding this, we more or less need to revert that commit here (which I can do by hand) so users can use spring to speed up packwerk. It seems like that too can go in a separate PR that comes before this. I am not super familiar with how Spring works -- is it that we are calling Given this, it seems like the path forward is:
Does this seem right to you? |
That plan seems good to me, but I'm not a spring expert myself - it'd be good to have @rafaelfranca 's opinion. I'm pretty sure he has opinions on exactly how spring should be used here. |
Sounds good. @rafaelfranca I'd love some guidance from you here. I'm a little confused about the mental model for how spring comes into play here. Reading more at https://github.com/rails/spring, it seems like the user just needs to generate the binstub for Can you help me understand what (if anything) packwerk needs to do to support using spring with packwerk? |
So, I think this is the relevant part of the previous implementation, when packwerk did use spring:
Afterwards, requires should go through spring's cache. The way it was set up in I think that makes more sense than requiring the user to do additional work, as they very likely would execute I'm also pretty sure |
1192aac
to
5a9cb45
Compare
5a9cb45
to
6da1bba
Compare
6da1bba
to
ca496dc
Compare
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.
Exciting stuff!
Just clean up the commit history and this is ready to go.
Love all that removed complexity.
ca496dc
to
702d2dc
Compare
@exterm Squashed it into a single commit! |
Wanted to do a last test run against the monolith, but am getting a strange sorbet error that doesn't look related at all. Will have to take some time to look into this. |
Interesting -- if you're able to post the output I may be able to help! |
Turned out that somehow an incompatible version of I cut a release |
Summary
Caching load paths was done to optimize start-up time so that
packwerk check
on a single file is fast. After some discussion (see slack thread at bottom), we think it may be a better tradeoff to no longer cache load paths and instead load the rails application. The reason for this was that it was a pain to add toload_paths
. In the happy path, a user remembers that they need to do this, and they runbin/packwerk validate
prior to updating deprecations and they use the error message to copy and paste intopackwerk.yml
.In the unhappy path, a user:
update-deprecations
. No new violations are found sinceload_paths
wasn't updated.bin/packwerk validate
packwerk.yml
bin/packwerk update-deprecations
again.Spring
We are still investigating what it would mean for spring to continue to help optimize boot time given the change. One option here would be to tell spring to watch certain files and folders. We can have packwerk inject to that list and write a digest totmp
, so when packwerk paths are updated, it instructs spring to reload. If necessary, we can delve into this deeper prior to landing.We reenabled spring here: #153
What are you trying to accomplish?
Remove need to cache
load_paths
inpackwerk.yml
.What approach did you choose and why?
I chose to use the current implementation of generating the
load_paths
when the configuration file is generated so that the behavior is identical. I kept the API to configuration the same for clients, and explicitly raised an error in places that today expect errors to be raised when a non-rails application attempts to use packwerk. I found these places by the failures in in the test suite.What should reviewers focus on?
Reviewers may want to focus on:
packwerk.yml
, and now may cache fromspring
Type of Change
Additional Release Notes
load_paths
inpackwerk.yml
is now deprecated. The user will receive a deprecation warning if they have this configuration to help prompt them to remove it. A subsequent version can raise instead.Checklist
Slack thread