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鈥檒l occasionally send you account related emails.

Already on GitHub? Sign in to your account

Sporadic errors "LoadError: no such file to load -- sass" with JRuby and Sprockets #23

Closed
chadlwilson opened this issue Sep 11, 2022 · 19 comments

Comments

@chadlwilson
Copy link

chadlwilson commented Sep 11, 2022

I'm not really sure what is going on here, but would appreciate any tips - please go gentle, I'm not a Rails/Sprockets expert 馃槄. Apologies if this should be reported at the other project; I'm not really sure.

When working in development mode with hot-reloading and the autoloader, every now and then (but reasonably frequently) I get the below error. I can't work out a pattern as to what is happening. When this happens the browser will block. If I kill the request and try again it will usually work OK but then occur again later.

I have also had it happen when pre-compiling assets too, so perhaps it is to do with some kind of race condition or threading type of issue with JRuby or sprockets? If you suspect I need to upgrade to Sprockets 4, that's fine. Haven't noticed a similar issue earlier when using ruby-sass.

warning: thread "Ruby-0-Thread-4163: /Users/chad/Projects/community/gocd/gocd/server/src/main/webapp/WEB-INF/rails/gems/jruby/2.6.0/bundler/gems/sass-embedded-host-ruby-0d103fd1936a/lib/sass/embedded/dispatcher.rb:18" terminated with exception (report_on_exception is true):
LoadError: no such file to load -- sass
                require at org/jruby/RubyKernel.java:1017
                require at /Users/chad/Projects/community/gocd/gocd/server/src/main/webapp/WEB-INF/rails/gems/jruby/2.6.0/gems/zeitwerk-2.6.0/lib/zeitwerk/kernel.rb:35
                 <main> at /Users/chad/Projects/community/gocd/gocd/server/src/main/webapp/WEB-INF/rails/gems/jruby/2.6.0/gems/sprockets-3.7.2/lib/sprockets/autoload/sass.rb:1
                require at org/jruby/RubyKernel.java:1017
                require at /Users/chad/Projects/community/gocd/gocd/server/src/main/webapp/WEB-INF/rails/gems/jruby/2.6.0/gems/zeitwerk-2.6.0/lib/zeitwerk/kernel.rb:35
              asset_url at /Users/chad/Projects/community/gocd/gocd/server/src/main/webapp/WEB-INF/rails/gems/jruby/2.6.0/gems/sprockets-3.7.2/lib/sprockets/sass_processor.rb:137
               font_url at /Users/chad/Projects/community/gocd/gocd/server/src/main/webapp/WEB-INF/rails/gems/jruby/2.6.0/gems/sprockets-3.7.2/lib/sprockets/sass_processor.rb:209
                  setup at /Users/chad/Projects/community/gocd/gocd/server/src/main/webapp/WEB-INF/rails/gems/jruby/2.6.0/gems/sassc-embedded-1.54.0/lib/sassc/embedded.rb:151
          function_call at /Users/chad/Projects/community/gocd/gocd/server/src/main/webapp/WEB-INF/rails/gems/jruby/2.6.0/bundler/gems/sass-embedded-host-ruby-0d103fd1936a/lib/sass/embedded/host/function_registry.rb:50
  function_call_request at /Users/chad/Projects/community/gocd/gocd/server/src/main/webapp/WEB-INF/rails/gems/jruby/2.6.0/bundler/gems/sass-embedded-host-ruby-0d103fd1936a/lib/sass/embedded/host.rb:119
            public_send at org/jruby/RubyKernel.java:2003
        receive_message at /Users/chad/Projects/community/gocd/gocd/server/src/main/webapp/WEB-INF/rails/gems/jruby/2.6.0/bundler/gems/sass-embedded-host-ruby-0d103fd1936a/lib/sass/embedded/dispatcher.rb:80

Environment:
JRuby 9.3.7.0 (Ruby 2.6 compatible)
Rails 6.1.6.1 in Zeitwork mode
Sprockets 3.7.2 (haven't yet moved to 4.1, was earlier blocked by another dependency)

@ntkme
Copy link
Member

ntkme commented Sep 11, 2022

Assuming you鈥檙e trying to use the shim for sassc, you will have to make sure all Sass related configs are referring sassc rather than sass or you may see this error.

@chadlwilson
Copy link
Author

Hmm, that does seem similar - however doesn't seem to explain why it's mostly working just fine, but occasionally fails? We're not overriding any defaults for the css_compressor at all right now.

I did have sassc working earlier with Sprockets 3.7.x as well before switching to sass-embedded due to issues with Windows.

If you think there's something in Sprockets 4 likely required for it to be better behaved here, I suppose I'll have to try and upgrade that too. 馃槵

@ntkme
Copy link
Member

ntkme commented Sep 11, 2022

Here is my educated guess: you have sassc installed, but it was never used by sprockets 3.x. You probably have sass somehow available in Ruby's $LOAD_PATH like the reporter of the other issue, so it happens to work sometimes. E.g. rake and bundle exec rake have different $LOAD_PATH.

@chadlwilson
Copy link
Author

Ok, thanks a lot. Pretty sure I don't have sass available anywhere, but regardless will try again with Sprockets 4. 馃檹

@chadlwilson chadlwilson closed this as not planned Won't fix, can't repro, duplicate, stale Sep 11, 2022
@chadlwilson
Copy link
Author

chadlwilson commented Sep 11, 2022

For what it's worth, I'm still able to get this on Sprockets 4, but ran out of time to figure out what is going on. Somehow the sass_processor is being used rather than sassc_processor at times.

warning: thread "Ruby-0-Thread-1672: /Users/chad/Projects/community/gocd/gocd/server/src/main/webapp/WEB-INF/rails/gems/jruby/2.6.0/bundler/gems/sass-embedded-host-ruby-0d103fd1936a/lib/sass/embedded/dispatcher.rb:18" terminated with exception (report_on_exception is true):
LoadError: no such file to load -- sass
                require at org/jruby/RubyKernel.java:1017
                require at /Users/chad/Projects/community/gocd/gocd/server/src/main/webapp/WEB-INF/rails/gems/jruby/2.6.0/gems/zeitwerk-2.6.0/lib/zeitwerk/kernel.rb:35
                 <main> at /Users/chad/Projects/community/gocd/gocd/server/src/main/webapp/WEB-INF/rails/gems/jruby/2.6.0/gems/sprockets-4.1.1/lib/sprockets/autoload/sass.rb:2
                require at org/jruby/RubyKernel.java:1017
                require at /Users/chad/Projects/community/gocd/gocd/server/src/main/webapp/WEB-INF/rails/gems/jruby/2.6.0/gems/zeitwerk-2.6.0/lib/zeitwerk/kernel.rb:35
              asset_url at /Users/chad/Projects/community/gocd/gocd/server/src/main/webapp/WEB-INF/rails/gems/jruby/2.6.0/gems/sprockets-4.1.1/lib/sprockets/sass_processor.rb:158
              image_url at /Users/chad/Projects/community/gocd/gocd/server/src/main/webapp/WEB-INF/rails/gems/jruby/2.6.0/gems/sprockets-4.1.1/lib/sprockets/sass_processor.rb:176
                  setup at /Users/chad/Projects/community/gocd/gocd/server/src/main/webapp/WEB-INF/rails/gems/jruby/2.6.0/gems/sassc-embedded-1.54.0/lib/sassc/embedded.rb:151
          function_call at /Users/chad/Projects/community/gocd/gocd/server/src/main/webapp/WEB-INF/rails/gems/jruby/2.6.0/bundler/gems/sass-embedded-host-ruby-0d103fd1936a/lib/sass/embedded/host/function_registry.rb:50
  function_call_request at /Users/chad/Projects/community/gocd/gocd/server/src/main/webapp/WEB-INF/rails/gems/jruby/2.6.0/bundler/gems/sass-embedded-host-ruby-0d103fd1936a/lib/sass/embedded/host.rb:119
            public_send at org/jruby/RubyKernel.java:2003
        receive_message at /Users/chad/Projects/community/gocd/gocd/server/src/main/webapp/WEB-INF/rails/gems/jruby/2.6.0/bundler/gems/sass-embedded-host-ruby-0d103fd1936a/lib/sass/embedded/dispatcher.rb:80

@ntkme ntkme reopened this Sep 11, 2022
@ntkme
Copy link
Member

ntkme commented Sep 11, 2022

sass/sassc-rails#114 seems to be related here.

@ntkme ntkme transferred this issue from sass-contrib/sass-embedded-host-ruby Sep 11, 2022
@chadlwilson
Copy link
Author

chadlwilson commented Sep 12, 2022

Ahh, yes. I was wondering about that.

Funnily enough I just recently re-introduced (a couple of weeks ago) use of the assets block (we had got rid of it with the Rails 5 upgrade) - to avoid packaging the massive sassc
and dart-sass extensions/native bins during production runtime which should not be needed when one is precompiling assets. sassc in particular was adding 50MB of binaries to our installer size. During dev and assets compile they are there though, along with RAILS_GROUPS=assets and specific bundler require logic.

But I'll dig further later and try without to confirm the source of the issue and see if I can find an alternate approach.

@chadlwilson
Copy link
Author

Sadly I still seem to be able to replicate the issue with everything outside the assets group, so I guess I need to keep digging :'(

source 'https://rubygems.org'
ruby '2.6.8'

gem 'rails'
gem 'sassc-rails'
gem 'sassc', github: 'sass/sassc-ruby', ref: 'refs/pull/233/head'
gem 'sassc-embedded'
gem 'sass-embedded', github: 'ntkme/sass-embedded-host-ruby', ref: 'main'
gem 'js-routes'
gem 'ts_routes'

# Windows does not include zoneinfo files, so bundle the tzinfo-data gem
gem 'tzinfo-data', platforms: [:mingw, :mswin, :x64_mingw, :jruby]

group :development, :test do
  # make sure to `System.setProperty("jruby.runtime.arguments", "--debug")` before opening up pry
  gem 'pry-debugger-jruby', platforms: :jruby
end

group :test do
  gem 'capybara'
  gem 'rspec-rails'
  gem 'rspec-instafail', require: false
  gem 'rspec_junit_formatter'
  gem 'rails-controller-testing'
end

@chadlwilson
Copy link
Author

The only pattern I can find here is that

  • if it fails, it always seems to happen on the first call into to a custom_function for a given render
  • I can only replicate it in cases where the call that fails is a font_url call and seemingly when I change scss files that have font loading in them
  • if I rescue the LoadError in embedded.rb and then keep going and recompiling the same file, it seems to become very difficult to replicate after that. No idea why.

Still no real ideas though.

@ntkme
Copy link
Member

ntkme commented Sep 13, 2022

Here is how it works:

  1. Sprockets::SassProcessor::SassFunctions, which is equivelent to Sprockets::SassFunctions, are created for sass: https://github.com/rails/sprockets/blob/f4d3dae71ef29c44b75a49cfbf8032cce07b423a/lib/sprockets/sass_processor.rb#L110
  2. Sprockets::SassFunctions has one function added, for sassc https://github.com/sass/sassc-rails/blob/master/lib/sassc/rails/functions.rb
  3. SassC::Rails::SassTemplate::Functions, this redefines functions created for sass and changes them to sassc: https://github.com/sass/sassc-rails/blob/8d0462d54b5b5dd84cb1df31823c3afaebb64534/lib/sassc/rails/template.rb#L85 https://github.com/sass/sassc-rails/blob/8d0462d54b5b5dd84cb1df31823c3afaebb64534/lib/sassc/rails/template.rb#L15

Step 3 is supposed to override the functions defined in step 1 to prevent calling sass, I think what happened is a loading order issue that step 1 happened after step 3 for some reasons. Or somehow step 3 is not happening.

@ntkme
Copy link
Member

ntkme commented Sep 13, 2022

If you can add some log in the 3 files that have been mentioned above, and see how they are getting loaded, I think it will help understand the problem.

@chadlwilson
Copy link
Author

I tried a bit of logging in the various files, in initializers, and in the asset_url calls, but I couldn't really see anything being re-loaded or anything weird like that after first start.

I'd just see a single call in the about-to-fail compile to a non-overridden Sprockets::SassProcessor.asset_url rather than the redefined one in SassC::Rails::SassTemplate::Functions.asset_url as for the "OK" compiles. Possibly reaching the limits of my knowledge for digging into Ruby-land right now unless I put in quite a bit more time investment. Hmm.

It's also quite possible it has nothing to do with sassc-embedded-shim-ruby and is thus a waste of your time, which is not my intention!

@chadlwilson
Copy link
Author

Will close this for now, on the assumption that it's something in my environment, a problem within sassc-rails or something with sprockets/zeitwork/whatever - and likely nothing to do with this tool.

My only suggestion for the sassc-embedded tool would perhaps be that it'd be good if it doesn't just hang with such errors; which seems to be caused by the embedded part not handling this particular Exception and sending an error/response back to the main request handler, instead the thread seems to just die and the caller sits there waiting for a response rather than being able to, say, render a Rails error page etc.

https://github.com/ntkme/sassc-embedded-shim-ruby/blob/ece7213c41489d09b60a4c9c10a9edf1a2ed5cb7/lib/sassc/embedded.rb#L147-L159

@ntkme
Copy link
Member

ntkme commented Sep 15, 2022

@chadlwilson The problem is due to lack of thread safety in Sprockets::Utils.module_include which is called here.

@chadlwilson
Copy link
Author

Oh wow. Any suggestions of whether that can be mitigated on the user side?

@ntkme
Copy link
Member

ntkme commented Sep 15, 2022

I even got a mininum reproduction for this:

# Gemfile
source "https://rubygems.org"

# uncomment the comment in the next line to test the patch
gem 'sprockets' #, github: 'ntkme/sprockets', branch: 'module-include-thread-safety'
gem 'sassc-rails'
gem 'sassc', github: 'sass/sassc-ruby', ref: 'refs/pull/233/head'
gem 'sassc-embedded'
# test.rb
require 'sassc/rails'

class MockContext < Hash
  def metadata
    {}
  end

  def asset_path(path, options)
    "#{path}"
  end
end

class MockEnvironment
  def context_class
    MockContext
  end

  def paths
    []
  end
end

class MockSassConfig
  def inline_source_maps
    false
  end

  def line_comments
    false
  end

  def style
    :expanded
  end

  def load_paths
    []
  end
end

class MockConfig
  def sass
    MockSassConfig.new
  end
end

class MockApplication
  def config
    MockConfig.new
  end
end

module Rails
  def self.application
    MockApplication.new
  end
end

threads = []
10.times do
  threads << Thread.new do
    puts SassC::Rails::SassTemplate.call({
      data: '''
        sass
          a: asset_url("test")
      ''',
      environment: MockEnvironment.new
    })
  end
end

threads.each do |t|
  t.join
end

@chadlwilson
Copy link
Author

Monkey patch a mutex around module_include somehow? 馃槄

@chadlwilson chadlwilson closed this as not planned Won't fix, can't repro, duplicate, stale Sep 15, 2022
@ntkme
Copy link
Member

ntkme commented Sep 15, 2022

Yes, I tested locally and that definitely works. I will submit a PR to upstream to fix it.

@chadlwilson
Copy link
Author

Looks like they are still merging PRs on Sprockets and periodically releasing which is promising if there's any chance of addressing it upstream.

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

2 participants