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 config.before_eager_load #5182

Merged
merged 1 commit into from
Dec 5, 2024

Conversation

gmcgibbon
Copy link
Contributor

We want to make sure the gem is fully loaded in a production context before the application begins eagerly loading, otherwise we emit a warning. So, let's use config.before_eager_load to make sure gem eager loading happens before the app.

Before:

> RAILS_ENV=production bin/rails runner ""
GraphQL-Ruby thinks this is a production deployment but didn't eager-load its constants. Address this by:

  - Calling `GraphQL.eager_load!` in a production-only initializer or setup hook
  - Assign `GraphQL.env = "..."` to something _other_ than `"production"` (for example, `GraphQL.env = "development"`)

More details: https://graphql-ruby.org/schema/definition#production-considerations

After:

RAILS_ENV=production bin/rails runner ""

We want to make sure the gem is fully loaded in a production context
before the application begins eagerly loading, otherwise we emit a
warning. So, let's use config.before_eager_load to make sure gem eager
loading happens before the app.
@rmosolgo
Copy link
Owner

rmosolgo commented Dec 5, 2024

Awesome, thanks!

@rmosolgo rmosolgo merged commit 119e13b into rmosolgo:master Dec 5, 2024
13 of 15 checks passed
@rmosolgo rmosolgo added this to the 2.4.6 milestone Dec 5, 2024
@gmcgibbon gmcgibbon deleted the use_before_eager_load branch December 5, 2024 19:55
@sealabcore
Copy link

Looks like we are still getting this logger message on the latest version. Anything else I can try / info I can send over to help track it down?

Screenshot 2024-12-05 at 2 59 01 PM

@rmosolgo
Copy link
Owner

rmosolgo commented Dec 6, 2024

Ugh, sorry 😖 Yes, to help debug, It'd be great to get a backtrace when that warning is created. That would show exactly what part of Rails caused GraphQL::Schema to be loaded.

Here's a branch that will print the backtrace when that warning happens: #5185

Does it print if you start the rails server locally? Could you bundle that version and share the backtrace? For example:

gem "graphql", github: "rmosolgo/graphql-ruby", ref: "debug-eager-load-warning"

(You could also bundle open graphql and add that line of code yourself.) If you can share that backtrace, maybe it will have a clue about why our eager-loading hasn't already happened by that point!

@jgarber623-cargosense
Copy link

@rmosolgo Here's what I see in an app I'm working on using the github/ref combo from your comment above:

/usr/local/bundle/bundler/gems/graphql-ruby-c8550ac5025e/lib/graphql/schema.rb:50:in `<main>'
/usr/local/lib/ruby/3.3.0/bundled_gems.rb:69:in `require'
/usr/local/lib/ruby/3.3.0/bundled_gems.rb:69:in `block (2 levels) in replace_require'
/usr/local/bundle/gems/bootsnap-1.18.4/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:30:in `require'
/usr/local/bundle/gems/zeitwerk-2.7.1/lib/zeitwerk/core_ext/kernel.rb:34:in `require'
/usr/local/bundle/bundler/gems/graphql-ruby-c8550ac5025e/lib/graphql/introspection/base_object.rb:4:in `<module:Introspection>'
/usr/local/bundle/bundler/gems/graphql-ruby-c8550ac5025e/lib/graphql/introspection/base_object.rb:3:in `<module:GraphQL>'
/usr/local/bundle/bundler/gems/graphql-ruby-c8550ac5025e/lib/graphql/introspection/base_object.rb:2:in `<main>'
/usr/local/lib/ruby/3.3.0/bundled_gems.rb:69:in `require'
/usr/local/lib/ruby/3.3.0/bundled_gems.rb:69:in `block (2 levels) in replace_require'
/usr/local/bundle/gems/bootsnap-1.18.4/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:30:in `require'
/usr/local/bundle/gems/zeitwerk-2.7.1/lib/zeitwerk/core_ext/kernel.rb:34:in `require'
/usr/local/bundle/bundler/gems/graphql-ruby-c8550ac5025e/lib/graphql/introspection.rb:107:in `<main>'
/usr/local/lib/ruby/3.3.0/bundled_gems.rb:69:in `require'
/usr/local/lib/ruby/3.3.0/bundled_gems.rb:69:in `block (2 levels) in replace_require'
/usr/local/bundle/gems/bootsnap-1.18.4/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:30:in `require'
/usr/local/bundle/gems/zeitwerk-2.7.1/lib/zeitwerk/core_ext/kernel.rb:34:in `require'
/usr/local/bundle/gems/graphql-client-0.24.0/lib/graphql/client.rb:71:in `<class:Client>'
/usr/local/bundle/gems/graphql-client-0.24.0/lib/graphql/client.rb:26:in `<module:GraphQL>'
/usr/local/bundle/gems/graphql-client-0.24.0/lib/graphql/client.rb:19:in `<main>'
<internal:/usr/local/lib/ruby/3.3.0/rubygems/core_ext/kernel_require.rb>:37:in `require'
<internal:/usr/local/lib/ruby/3.3.0/rubygems/core_ext/kernel_require.rb>:37:in `require'
/usr/local/lib/ruby/3.3.0/bundled_gems.rb:69:in `block (2 levels) in replace_require'
/usr/local/bundle/gems/zeitwerk-2.7.1/lib/zeitwerk/core_ext/kernel.rb:34:in `require'
/usr/local/lib/ruby/3.3.0/bundler/runtime.rb:73:in `rescue in block in require'
/usr/local/lib/ruby/3.3.0/bundler/runtime.rb:51:in `block in require'
/usr/local/lib/ruby/3.3.0/bundler/runtime.rb:44:in `each'
/usr/local/lib/ruby/3.3.0/bundler/runtime.rb:44:in `require'
/usr/local/lib/ruby/3.3.0/bundler.rb:212:in `require'
/workspaces/dummy/config/application.rb:9:in `<main>'
/usr/local/lib/ruby/3.3.0/bundled_gems.rb:69:in `require'
/usr/local/lib/ruby/3.3.0/bundled_gems.rb:69:in `block (2 levels) in replace_require'
/usr/local/bundle/gems/bootsnap-1.18.4/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:30:in `require'
/usr/local/bundle/gems/railties-7.1.4.1/lib/rails/command/actions.rb:15:in `require_application!'
/usr/local/bundle/gems/railties-7.1.4.1/lib/rails/command/environment_argument.rb:31:in `require_application!'
/usr/local/bundle/gems/railties-7.1.4.1/lib/rails/command/actions.rb:19:in `boot_application!'
/usr/local/bundle/gems/railties-7.1.4.1/lib/rails/commands/console/console_command.rb:105:in `perform'
/usr/local/bundle/gems/thor-1.3.2/lib/thor/command.rb:28:in `run'
/usr/local/bundle/gems/thor-1.3.2/lib/thor/invocation.rb:127:in `invoke_command'
/usr/local/bundle/gems/railties-7.1.4.1/lib/rails/command/base.rb:178:in `invoke_command'
/usr/local/bundle/gems/thor-1.3.2/lib/thor.rb:538:in `dispatch'
/usr/local/bundle/gems/railties-7.1.4.1/lib/rails/command/base.rb:73:in `perform'
/usr/local/bundle/gems/railties-7.1.4.1/lib/rails/command.rb:71:in `block in invoke'
/usr/local/bundle/gems/railties-7.1.4.1/lib/rails/command.rb:149:in `with_argv'
/usr/local/bundle/gems/railties-7.1.4.1/lib/rails/command.rb:69:in `invoke'
/usr/local/bundle/gems/railties-7.1.4.1/lib/rails/commands.rb:18:in `<main>'
/usr/local/lib/ruby/3.3.0/bundled_gems.rb:69:in `require'
/usr/local/lib/ruby/3.3.0/bundled_gems.rb:69:in `block (2 levels) in replace_require'
/usr/local/bundle/gems/bootsnap-1.18.4/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:30:in `require'
bin/rails:4:in `<main>'
GraphQL-Ruby thinks this is a production deployment but didn't eager-load its constants. Address this by:

  - Calling `GraphQL.eager_load!` in a production-only initializer or setup hook
  - Assign `GraphQL.env = "..."` to something _other_ than `"production"` (for example, `GraphQL.env = "development"`)

More details: https://graphql-ruby.org/schema/definition#production-considerations
Loading production environment (Rails 7.1.4.1)

The app is using the graphql-client gem which, when present in Gemfile, triggers the "production deployment" warning:

gem "graphql", github: "rmosolgo/graphql-ruby", ref: "debug-eager-load-warning"
gem "graphql-client"

If I remove graphql-client from Gemfile, re-run bundle, and issue the same command (e.g. RAILS_ENV=production bin/rails runner "" as noted above), I do not see the backtrace or warning.

I don't know enough about the internals of this gem or the graphql-client gem to confidently say which is more responsible for triggering the warning. But! I wanted to share the experience in hopes that it helps sort out a fix or enhancement.

@gmcgibbon
Copy link
Contributor Author

gmcgibbon commented Dec 6, 2024

Ideally, if GraphQL client gem uses parts of this GraphQL gem, it would make sense for it to also be autoloaded. As for #5182 (comment), I would suspect something similar like a gem dependency is loading GraphQL before we expect it to. I need a backtrace to verify, though.

The problem mainly stems from the warning assuming that the schema will be loaded by the app, but it could be loaded by any dependent library at bundler require time. Most gems don't bother with this warning, and this may be part of why. We don't control what loads our code in consuming apps, and the worst case scenario is in more exotic use-cases, we don't load as much as we really should upfront (but it still works).

Happy to submit a patch to the client in the meantime.

@rmosolgo
Copy link
Owner

rmosolgo commented Dec 6, 2024

Yeah, I'm inclined to remove this warning since I can't exactly nail down when it should be logged: #5187

What do you think, @gmcgibbon ?

@gmcgibbon
Copy link
Contributor Author

I agree removing it is probably the least error-prone and more future proof) approach. Let's remove it.

@rmosolgo
Copy link
Owner

rmosolgo commented Dec 7, 2024

I removed it altogether and shipped 2.4.7. Thanks for your help tracking this down, everyone, and sorry the trouble along the way!

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.

4 participants