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

Auto-loading consumers from a Rails 6 app requires using classic autoloader #331

Open
jtrees opened this issue Jul 1, 2019 · 10 comments
Open

Comments

@jtrees
Copy link

jtrees commented Jul 1, 2019

Summary

Currently Hutch does not work with Rails 6 (rc1) out-of-the-box since the latter defaults to using Zeitwerk for autoloading paths.

Steps to Reproduce

  1. Generate a new Rails 6 application.
  2. Add hutch as a dependency.
  3. Create a consumer under <rails_root>/app/consumers/foo_consumer.rb.
  4. Ensure RabbitMQ is running.
  5. Run Hutch from the Rails root directory like so: bundle exec hutch --autoload-rails

Expected Result

The output should include lines such as these:

2019-07-01T15:54:24Z 6 INFO -- found rails project (.), booting app in development environment
<...>
2019-07-01T15:54:24Z 6 INFO -- setting up queues
2019-07-01T15:54:24Z 6 INFO -- setting up queue: consumers:foo_consumer

Actual Result

The output looks more like this:

2019-07-01T15:47:48Z 6 INFO -- found rails project (.), booting app in development environment
<...>
2019-07-01T15:47:48Z 6 WARN -- no consumer loaded, ensure there's no configuration issue
2019-07-01T15:47:48Z 6 INFO -- setting up queues

Known Workaround

Add the following to <rails_root>/config/application.rb:

config.autoloader = :classic
@michaelklishin
Copy link
Member

What can Hutch do about this?

@michaelklishin michaelklishin changed the title Auto-loading consumers from a Rails 6 app (via Zeitwerk) does not work Auto-loading consumers from a Rails 6 app requires using classic autoloader Jul 2, 2019
@pzac
Copy link
Contributor

pzac commented Feb 12, 2020

I've got this issue, too, and I see that the consumers are registered when the Hutch::Consumer mixin is included and this doesn't seem to play well with the development environment's lazy loading.
As a temporary fix one can set config.eager_load to true or trigger the consumers' autoloading in an initializer, but I'm wondering if there are better ways to handle this issue.

@michaelklishin
Copy link
Member

I'm not familiar with this Rails autoloader but in general, you have one lazy init code path that's unaware of another lazy init code path. Something (such as eager load) has to kick the tires. In case of Rails, it probably should be driven by Rails and not Hutch?

@pzac
Copy link
Contributor

pzac commented Feb 13, 2020

I guess so, or the consumers registration could happen differently - I'm not sure what would work best, though.
After some study I've found a better workaround for a Rails 6 app using the new zeitwerk loader, ie an initializer like this:

autoloader = Rails.autoloaders.main

Dir.glob(File.join("**", "*_consumer.rb")).each do |consumer|
  autoloader.preload(consumer)
end

@michaelklishin
Copy link
Member

michaelklishin commented Feb 13, 2020 via email

@pzac
Copy link
Contributor

pzac commented Feb 14, 2020

Will do, and would be glad to have some zeitwerk expert to chime in if there are better ways to tackle this issue

@pzac
Copy link
Contributor

pzac commented Feb 14, 2020

Here it is, feel free to edit/improve/close: #342

@connorshea
Copy link

That preload method is deprecated and was removed in Zeitwerk 2.5, released last October: https://github.com/fxn/zeitwerk/blob/eec3fb6b66394c9f04b15cff3821aca68470d1aa/CHANGELOG.md#250-20-october-2021

I'm not sure if the on_setup block is a sufficient replacement?

@connorshea
Copy link

If you're on Zeitwerk >2.5 and Ruby >=2.7 (I think that's when descendants was introduced?) and have a class that all your consumers descend from, adding this to your hutch.rb initializer seems to work:

Rails.autoloaders.main.on_setup do
  CustomConsumerClass.descendants.each { |cname| const_get(cname) }
end

Although I can't figure out how to get code reloading to work, I need to reboot the hutch process entirely for changes to get picked up (that was true before this change as well).

@michaelklishin
Copy link
Member

I'd happily adopt a PR that focuses on Rails 6+ and retains compatibility with the previous autoloader if, say, the user opts-in by requiring a specific Hutch file.

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

No branches or pull requests

4 participants