Search code examples
ruby-on-railsruby-on-rails-5requireautoloadeager-loading

Why is Rails trying to autoload this file in a production environment?


This is Rails v5.2.3. I have a particular Sidekiq job where many instances of the job seem to hang for 20+ minutes. In the same machine the queue resides on, while this is happening, I can run the same code in a Rails console and it finishes in 5 seconds.

I determined the offending PID from the Sidekiq screen, and ran:

kill -TTIN <pid>

The following lines appeared twice in the file, which I guess means that two threads from the same process were trying to load the same file:

Oct 13 17:04:08 myapp-production sidekiq[1217886]: /myapp/shared/bundle/ruby/2.6.0/gems/activesupport-5.2.3/lib/active_support/core_ext/module/introspection.rb:35:in `parent'
Oct 13 17:04:08 myapp-production sidekiq[1217886]: /myapp/shared/bundle/ruby/2.6.0/gems/activesupport-5.2.3/lib/active_support/dependencies.rb:516:in `load_missing_constant'
Oct 13 17:04:08 myapp-production sidekiq[1217886]: /myapp/shared/bundle/ruby/2.6.0/gems/activesupport-5.2.3/lib/active_support/dependencies.rb:195:in `const_missing'
Oct 13 17:04:08 myapp-production sidekiq[1217886]: /myapp/releases/20221013144458/lib/mixins/query_builder.rb:294:in `generate_sql'

I do have some requires in my code in different places, which I just determined is bad apparently. However, I'm not requireing the file listed above: lib/mixins/query_builder.rb. It is a module that is extended from a few different classes in lib/classes.

In my config/application.rb file, I have:

    config.enable_dependency_loading = true
    config.eager_load_paths += %W[
      #{config.root}/app/actions
      #{config.root}/app/organizers
      #{config.root}/lib/my_stuff
      #{config.root}/lib/mixins
      #{config.root}/lib/classes
    ]

    config.autoload_paths += %W[
      #{config.root}/app/actions
      #{config.root}/app/organizers
      #{config.root}/lib
      #{config.root}/lib/my_stuff
      #{config.root}/lib/mixins
      #{config.root}/lib/classes
      #{config.root}/lib/*

I admit that this is a mess, and I'm not sure what is going on here. I do have config.eager_load set to true in production and false in development.

So, if lib/mixins is present in both eager_load_paths and autoload_paths, why is the ActiveSupport's const_missing being triggered? And what should I do to remedy this situation?

Also, would I be better served by making this QueryBuilder an object that I can create an instance of to avoid two threads using the same program. In other words, is extend the wrong approach to lending the features within QueryBuilder to multiple classes?

As a second request, if anyone can point me in the right direction on the correct way to configure my eager_load_paths and autoload_paths, that will help a great deal prior to upgrading this app.

Thanks very kindly in advance for your help.


Solution

  • This is answer for "why I am seeing autoloads".

    Autoloading may still happen during eager loading.

    Let's imagine you have

    class Foo
      include QueryBuilder
    end
    

    If Rails is eager loading Foo and at that point lib/mixins/query_builder.rb was not been visited yet, the mere evaluation of foo.rb triggers the autoload of QueryBuilder in line 2.

    That configuration is a bit of a mess (as you said). We could work on simplifying it you liked.

    Why is the job taking +20 minutes and 5 in the console? Don't know if it is related to this. When Sidekiq launches, the application has booted and files have been eager loaded already.