NameError: uninitialized constant ApplicationSetting::DEFAULTS
This was first reported in https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/8573#note_21770307 and then https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/8573#note_22003969 and then in Slack: https://gitlab.slack.com/archives/development/p1485395848003264:
NameError: uninitialized constant ApplicationSetting::DEFAULTS
/var/cache/omnibus/src/gitlab-rails/lib/gitlab/current_settings.rb:41:in `fake_application_settings'
/var/cache/omnibus/src/gitlab-rails/lib/gitlab/current_settings.rb:12:in `ensure_application_settings!'
/var/cache/omnibus/src/gitlab-rails/lib/gitlab/current_settings.rb:7:in `current_application_settings'
This time, I think I got to the bottom of the issue, for real! :)
In production mode (i.e. RAILS_ENV=production
):
- We're auto-loading
ApplicationSetting
inconfig/initializers/1_settings.rb
- In
ApplicationSetting::DEFAULTS
we're referencingGitlab::ImportSources.values
- In
Gitlab::ImportSources.values
, we're referencingGitlab::GithubImport::Importer
- In
Gitlab::GithubImport::Importer
, we're includingGitlab::ShellAdapter
but it's not required at this time (it's only required inconfig/initializers/5_backend.rb
) and it's defined inlib/gitlab/backend/shell_adapter
so its proper namespace should beGitlab::Backend::ShellAdapter
!
By correcting the namespace of ShellAdapter
and Shell
to respectively Gitlab::Backend::ShellAdapter
and Gitlab::Backend::Shell
, it works again.
At this point you might wonder: why doesn't this happen in dev mode? That's because of how Rails auto-loading works:
- in development:
- it tries to auto-load dependencies using
Kernel#load
and rescuing the load if it fails so that the constant is still not defined, and raising the exception again: https://github.com/rails/rails/blob/master/activesupport/lib/active_support/dependencies.rb#L382-L383 - in our case, during the load,
ApplicationSetting::DEFAULTS
raises aNameError: uninitialized constant Gitlab::ShellAdapter
error becauseGitlab::ShellAdapter
is referenced inGitlab::GithubImport::Importer
, itself referenced inGitlab::ImportSources
) but is not defined at this time (and fails to be auto-loaded because its namespace is wrong) - in https://gitlab.com/gitlab-org/gitlab-ce/blob/master/config/initializers/1_settings.rb#L425 we're rescuing any exception that happens when calling
ApplicationSetting.expire
orCi::ApplicationSetting.expire
, includingNameError: uninitialized constant Gitlab::ShellAdapter
! - at this point
ApplicationSetting
is not defined because of the failure to defineApplicationSetting::DEFAULTS
- thus the next time
ApplicationSetting
is referenced is in https://gitlab.com/gitlab-org/gitlab-ce/blob/master/config/initializers/metrics.rb#L115 but this timeGitlab::ShellAdapter
has been explicitly required in https://gitlab.com/gitlab-org/gitlab-ce/blob/master/config/initializers/5_backend.rb#L5 so the auto-loading works
- it tries to auto-load dependencies using
- in production
- it uses
Kernel#require
without Rails "intelligence" to "retry" to auto-load an unknown dependency - we still rescue the
NameError: uninitialized constant Gitlab::ShellAdapter
error but this timeApplicationSetting
is defined (butApplicationSetting::DEFAULTS
is not!) so we don't have a second chance!
- it uses
I think there are a few issues here:
-
Gitlab::ShellAdapter
should beGitlab::Backend::ShellAdapter
=> this should solve the issue reported here. - We probably shouldn't require
lib/gitlab/backend/shell
orlib/gitlab/backend/shell_adapter
in https://gitlab.com/gitlab-org/gitlab-ce/blob/master/config/initializers/5_backend.rb, see http://guides.rubyonrails.org/autoloading_and_reloading_constants.html#require-dependency-and-initializers - We shouldn't rescue any exception in https://gitlab.com/gitlab-org/gitlab-ce/blob/master/config/initializers/1_settings.rb (this was added in 78c1ab40), we should either fix the code or rescue a particular exception