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

Autoload race condition: uninitialized constant errors #2255

Closed
f-mer opened this issue May 23, 2018 · 8 comments
Closed

Autoload race condition: uninitialized constant errors #2255

f-mer opened this issue May 23, 2018 · 8 comments

Comments

@f-mer
Copy link

f-mer commented May 23, 2018

This is more like a hypothesis than a straight bug report.

Expected behavior vs actual behavior

Using ActiveModelSerializers with a threaded web server (in my case puma) I get infrequent uninitialized constant errors. I think it's caused by the use of autoload. I guess that ActiveSupports autoload is not threadsafe and on application boot not all modules / classes are necessarily implicitly loaded.

Steps to reproduce

I'm not sure there is a way to reproduce. I think it's a race condition which only emerges under load.

Environment

ActiveModelSerializers Version (commit ref if not on tag): 0-10-stable

Output of ruby -e "puts RUBY_DESCRIPTION": ruby 2.4.0p0 (2016-12-24 revision 57164) [x86_64-linux]

Rails Version: 5.1.4

Errors

NameError: uninitialized constant ActiveModelSerializers::Adapter::JsonApi::ResourceIdentifier
NameError: uninitialized constant ActiveModelSerializers::Adapter::JsonApi::Relationship
NameError: uninitialized constant ActiveModelSerializers::Adapter::JsonApi::Deserialization

Additonal helpful information

I'm trying to solve the problem in this fork. Adding ActiveModelSerializers::Adapter::JsonApi to eager_load_namespaces in application.rb.

class Application < Rails::Application
  config.eager_load_namespaces << ActiveModelSerializers::Adapter::JsonApi
end

This problem might also be cause by the deactivation of dependency loading in rails 5?

@bf4
Copy link
Member

bf4 commented May 24, 2018

Interesting. I haven't run on Rails 5 yet.

In the past I have used an initializer with

ActiveSupport.on_load(:action_controller) do
  require 'active_model_serializers/register_jsonapi_renderer'
  ActiveModelSerializers.eager_load! if Rails.env.production?
  ActiveModelSerializers::Adapter::JsonApi.eager_load! if Rails.env.production?
  require 'active_model/serializer/null'
  ActiveModel::Serializer::Null
end

@bf4
Copy link
Member

bf4 commented May 24, 2018

How come you're not using a release?

@f-mer
Copy link
Author

f-mer commented May 24, 2018

From the ActiveSupport::Autoload source I draw the conclusion that calling eager_load! will have no effect without wrapping autoload calls inside eager_autoload blocks.

Went also with an initializer but loading the constants explicitly on boot:

ActiveModelSerializers::Deserialization
ActiveModelSerializers::Adapter::JsonApi::Relationship
ActiveModelSerializers::Adapter::JsonApi::ResourceIdentifier

Haven't seen the errors again since deployed.

Platformatec's blog post Eager loading for greater good is a good read on this topic.
But I'm not entirely sure what needs to go into eager_autoload blocks.

How come you're not using a release?

Oh, we are using 0.10.7. Got confused by the part in braces.

@bf4
Copy link
Member

bf4 commented Jun 25, 2018

Looks like we can add this to the docs as an FAQ of some sort, if you'd like to make a PR

@GeminPatel
Copy link

GeminPatel commented Sep 25, 2018

facing a similar issue:

uninitialized constant ActiveModelSerializers::Adapter::JsonApi::Meta
Did you mean? ActiveModelSerializers::Adapter::JsonApi::Meta

So what is the work around here? From what I understand, we can write all the constants in an initializer. Is a list or some way with which we can do this for all in a well-practiced manner?

Rails is 5.1.6
Ruby is 2.3.1
AMS is 0.10.7
Puma is 3.11.4 with 2 workers and 25 threads on each worker on each machine.

@bf4
Copy link
Member

bf4 commented Oct 4, 2018

@GeminPatel I'm not sure how Rails 5 would differ, but have you tried an initializer like what I described #2255 (comment)

@f-mer
Copy link
Author

f-mer commented Oct 8, 2018

Rails 5 unhooks autoloading (#a71350c) after the application has booted. I suspect the error originates from this gem not explicitly loading all deps during application boot.

The initializer is a workaround which actually forces autoloading during application boot.

@bf4 #3f65eba fixes the issue. Would you be interesetd in a pull request?

@bf4
Copy link
Member

bf4 commented Oct 8, 2018 via email

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

3 participants