0
0

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.

rspecで既存の並行処理に対してテストを追加したら fatal - No live threads left. Deadlock? エラーが起きた。

Last updated at Posted at 2020-01-28

rails5にて。
とある、パラレル処理を行っているコントローラーがあった。

イメージ

...
Parallel.each(records, :in_threads=>4) do |r|
  Blablabla::BullshitService.new(r.dead_beaf).bullshit
end
...

リファクタのためにrspecでrequestsのテストを書いていたら、実行時に
No live threads left. Deadlock?
というエラーになって失敗した。

イメージ


$ bundle exec rspec spec/requests/api/blablabla_controller_spec.rb

...

fatal - No live threads left. Deadlock?
4 threads, 4 sleeps current:0x000055d836b087e0 main thread:0x000055d82d7f48e0
* #<Thread:0x000055d82e208c88 sleep_forever>
   rb_thread_t:0x000055d82d7f48e0 native:0x00007ff40e623b68 int:1
   /bundle/gems/parallel-1.18.0/lib/parallel.rb:212:in `value'
   /bundle/gems/parallel-1.18.0/lib/parallel.rb:212:in `map'
   /bundle/gems/parallel-1.18.0/lib/parallel.rb:212:in `block (2 levels) in in_threads'
   /bundle/gems/parallel-1.18.0/lib/parallel.rb:211:in `handle_interrupt'
   /bundle/gems/parallel-1.18.0/lib/parallel.rb:211:in `block in in_threads'
   /bundle/gems/parallel-1.18.0/lib/parallel.rb:204:in `handle_interrupt'
   /bundle/gems/parallel-1.18.0/lib/parallel.rb:204:in `in_threads'
   /bundle/gems/parallel-1.18.0/lib/parallel.rb:353:in `work_in_threads'
   /bundle/gems/parallel-1.18.0/lib/parallel.rb:275:in `map'
   /bundle/gems/parallel-1.18.0/lib/parallel.rb:227:in `each'

...

  app/controllers/api/blablabla_controller.rb:66:in `bullshit'

   (0.6ms)  ROLLBACK
F

gemのparallelのどこかで不具合が起きているのかなと思いgem側のissueを確認した。
それっぽいのはあるが、自分のケースとはちがった。
ソースを確認しても、怪しそうなところの検討がつけられなかった。
(泣きながら)1つの処理しか並行動作しないようにしつつ binding.pry をかけて、stepで潜り始めたところ
すぐ次のようなframeにぶち当たり

    200: def const_missing(const_name)
 => 201:   from_mod = anonymous? ? guess_for_anonymous(const_name) : self
    202:   Dependencies.load_missing_constant(from_mod, const_name)
    203: end

railsのautoload のことを思い出す。

RAILS_ENV=production時は eager_load によって起動シーケンスですべてのクラスがロードされるが
test, developmentなどのときはautoloadにて都度読み込まれている。

rspecの該当箇所付近にてeager_load!を呼ぶようにしたところ、エラーが起こらなくなった。

Rails.application.eager_load!

Parallel.each の各blockにて、それぞれautoloadが起こって競合している模様。

autoloadの仕組みはthread-safeではなかったのか、、
テスト時に全部ロードするのはなんだか嫌だけど、requireを都度書くのも保守したくなくなりそう。
ベストプラクティスが知りたい。

_人人人人人人人人人人人人_
> pryつかいにくくない? <
 ̄Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^ ̄

see also

Rails 5 disables autoloading while app in production
https://blog.bigbinary.com/2016/08/29/rails-5-disables-autoloading-after-booting-the-app-in-production.html

0
0
0

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
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?