4
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

gem 'sprockets' 4.0での並列処理でデッドロックしてしまう問題について

Last updated at Posted at 2020-11-03

gem 'sprockets'について

seeetsファイルをコンパイルするライブラリ。
ただし、rails 5.1 からはjavascriptコンパイラにはwebpackerが推奨され、rails 6.0からはjavascriptコンパイラのデフォルトがwebpackerに変更されている。
現時点ではCSSやimageのコンパイルのデフォルトに使用されている。

CSS, image -> sprockets
javascript -> webpacker

現象

アセットプリコンパイルで実行結果が返ってこなくなります。

解決方法

1. 並行処理を無効にする設定を行う。

以下どちらかの設定をアプリケーションの設定で行うことで、並行処理を無効にし問題発生を回避します。

Rails.application.config.assets.export_concurrent = false
Sprockets.export_concurrent = false

2.sprocketsのバージョン3系を使用する

gem 'sprockets'のメンテナンスは遅く、修正まで時間がかかることが予想されるので3系を使うのも1つです。

詳細

Sprockets 4.0ではコンパイルのパフォーマンス向上のためにマルチスレッドで並行実行される様にな離ました。
See: https://github.com/rails/sprockets/pull/469

並行処理はConcurrent::Promiseを使用し、その後promises.each(&:wait!)wait!しています。

promises = args.flatten.map do |path|
  Concurrent::Promise.execute(executor: executor) do
    environment.find_all_linked_assets(path) do |asset|
      yield asset
    end
  end
end
promises.each(&:wait!)

See: https://github.com/rails/sprockets/pull/469/files#diff-0d972076f2fbe7a73281fcc0282e57a1618bba231bc8023a4d5bc5705fb06da7R123-R130

このとき、wait!メソッドでは処理が終わるまでtimeoutの時間待機するのですが、引数を指定していないためnilが入り、永遠に待ち続けます。

def wait!(timeout = nil)
  wait(timeout).tap { raise self if rejected? }
end

See: https://github.com/ruby-concurrency/concurrent-ruby/blob/ffed3c3c0518030b0ed245637703089fa1f0eeee/lib/concurrent/concern/obligation.rb#L79-L89

並行処理の中でデッドロックが発生した場合、アセットプリコンパイル処理が永遠に終わらない問題が発生します。
並行処理している中で、複数のスレッドが同一のファイルをコンパイルしようとしてデッドロックしているようです。
ruby-concurrencyのバグ?の可能性があるとのことです。
https://github.com/ruby-concurrency/concurrent-ruby/issues/870

また類似のissueも多く回っています。
See: https://github.com/rails/sprockets/issues?utf8=%E2%9C%93&q=is%3Aissue+is%3Aopen+thread+OR+concurrent

参考

https://github.com/rails/sprockets/issues/640
https://github.com/rails/sprockets/issues/581
https://github.com/ruby-concurrency/concurrent-ruby/issues/870
https://github.com/ruby-concurrency/concurrent-ruby/blob/ffed3c3c0518030b0ed245637703089fa1f0eeee/lib/concurrent/synchronization/lockable_object.rb#L6-L20

その他

sprocketsについての議論は以下のWTFのページも勉強になります。
https://discuss.rubyonrails.org/t/sprockets-abandonment/74371/24

4
1
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?