Skip to content
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

Use "main" reloader and cache resolvers from {append,prepend}_view_path #47347

Merged
merged 4 commits into from Feb 16, 2023

Conversation

jhawthorn
Copy link
Member

This fixes issues with runtime use of {append,prepend}_view_path and also rewrites ActionView::CacheExpiry to hook into the main reloaders rather than holding its own lock.

Supersedes #46345 and #47257

A potential downside is that this may cause increased reloading of classes in a dev environment, as previously view reloading was separate. I think that's acceptable as other components work that way (like i18n), if we want to improve it we can investigate in the future.

In order to track directories to watch for view changes, we added a callback around building of FileSystemResolvers, to start watching the directories of any newly created resolvers immediately after they're created. This should avoid us getting stuck in a reload loop where loading a controller class creates a new resolver which causes classes to be reloaded.

This should also fix issues with {append,prepend}_view_path when used at runtime (not at the class level). Previously the resolvers did not persist between requests and a new one was created each time. In order to do this we now keep any resolvers created around for the entire lifetime of the application, including (at least currently) in development.

cc @codener

@watcher.execute
else
@watcher.execute_if_updated
@previous_change ||= old_watcher&.updated?
Copy link
Member

Choose a reason for hiding this comment

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

Not really practical to cover the race in a test, so maybe worth a comment here noting that we specifically do the final query of the old watcher after the new one has been set up?

@ioquatix
Copy link
Contributor

ioquatix commented Feb 10, 2023

I've tested this branch and confirm it fixes the described issue of running Rails on Falcon.

Fixes socketry/falcon#166.

@codener
Copy link
Contributor

codener commented Feb 10, 2023

Awesome, thanks. I would not have been able to come up with such a profound solution 💪

@ioquatix
Copy link
Contributor

@jhawthorn can we merge this?

jhawthorn and others added 4 commits February 16, 2023 10:29
When prepending or appending view paths, Rails will create an ActionView::Resolver
for each String or Pathname argument. Previously, these were not cached. If view
paths were added in a request context (which is a common thing in a multi-tenant
application), new resolvers were created on each request. This effectively
disabled template caching for the added view paths.

Further, under certain circumstances, it also created a memory leak.

This commit fixes both issues by turning dynamic view path strings into cached
resolvers.

Co-authored-by: Dominik Schöler <dominik.schoeler@makandra.de>
Co-authored-by: John Hawthorn <john@hawthorn.email>
Co-authored-by: Matthew Draper <matthew@trebex.net>
@jhawthorn jhawthorn merged commit 9180e61 into rails:main Feb 16, 2023
@jhawthorn jhawthorn deleted the view_cache_main_reloader branch February 16, 2023 21:13
@ioquatix
Copy link
Contributor

Thanks this is amazing 🤩

@mculp
Copy link

mculp commented Feb 18, 2023

@jhawthorn did you happen to record any relative metrics for before and after this PR? I've seen some microbenchmarks in an older issue that pointed to this as the root cause. But I'm also curious if it'll affect real world performance.

@ioquatix
Copy link
Contributor

Based on prior discussions, isn't this only used in development?

@codener
Copy link
Contributor

codener commented Feb 20, 2023

As noted in #46345, the missing caching of dynamic invocations of prepend_view_paths almost tore down a production app, so I'd say No.

@espen
Copy link

espen commented Feb 20, 2023

@ioquatix it is used to render different layouts/views based on context set at runtime. For example one client should use theme1 while other theme2 (different paths).

nickborromeo added a commit to nickborromeo/rails that referenced this pull request Feb 24, 2023
This is a refactor of the `Registry` module added in rails#47347. This is an attempt to
minimize the namespace conflcits that will happen when users will have a top level `Registry` module which can cause
incorrect behavior

Replace ActionView::ViewPaths::Registry with ActionView::PathRegistry
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

6 participants