Ruby 2.6 Rails 6.0でMongoDBを使うとSegmentation Faultが起きたらconcurrent-rubyを疑え


一過性の高い記事です。

プロセスを終了するときにSegmentation Faultが起きる

RailsコンソールやRails runnerで、mongodbにデータを一括投入するバッチを走らせると

MONGODB | [25] mongodb:27017 | admin.endSessions | SUCCEEDED | 0.000s
[BUG] Segmentation fault at 0x0000000000000014
ruby 2.6.5p114 (2019-10-01 revision 67812) [x86_64-linux]
-- Control frame information -----------------------------------------------
c:0001 p:---- s:0003 e:000002 (none) [FINISH]
-- Machine register context ------------------------------------------------
 RIP: 0x00007f209f69725b RBP: 0x00007f208c6c9c80 RSP: 0x00007f208c6c9bd8
 RAX: 0x0000000000000014 RBX: 0x000055a9a45db430 RCX: 0x0000000000000000
 RDX: 0x0000000000000014 RDI: 0x000055a9a3da07a0 RSI: 0x00007f208c6c9c30
  R8: 0x0000000000000010  R9: 0x000055a99e9f4780 R10: 0x0000000000000010
 R11: 0x0000000000000246 R12: 0x000055a9a2be1fd0 R13: 0x0000000000000000
 R14: 0x000055a9a40b3510 R15: 0x000055a9a248b2e8 EFL: 0x0000000000010206
-- C level backtrace information -------------------------------------------
root@a46ce56df74d:/usr/src/app# 

こんなかんじで、RailsコンソールをexitしたタイミングでSegmentation Faultが起きた。

なるほどわからない。

ググっても有用な情報は出てこない

「mongo segmentation fault」 とか 「mongoid segmentation fault」だと、古いRubyバージョンの情報ばっかり出てくるのである。

MongoDB+Rubyの組み合わせで起きてるのか、Railsのバージョン依存で起きてるのか、Mongoidで起きてるのか、などなど、まったく見当がつかなかったので、切り分けを試みた。

  • Mongoidを使わず、mongodbのRubyドライバを直で使うと? →Segmentation Fault発生。Mongoidはシロ。
  • Ruby 2.5だと? →Segmentation Fault発生

・・・結局ようわからん。

そんななか、たまたま「mongoid Rails6 Segmentation Fault」で

https://github.com/rails/rails/issues/37004

こんなことを書いてる人が居た。

concurrent-rubyのバグ?

なんかとてもそれっぽいのがあった。(私が見つけたわけではなく、会社の先輩が発見した。神...!!)

なんとなくconcurrent-rubyを1.1.6系にあげてみると・・・

[4] pry(main)> exit
MONGODB | EVENT: #<ServerDescriptionChanged address=mongodb:27017 topology=Single[mongodb:27017] prev=#<Mongo::Server:Description:0x47071403801000 config={"ismaster"=>true, "maxBsonObjectSize"=>16777216, "maxMessageSizeBytes"=>48000000, "maxWriteBatchSize"=>100000, "localTime"=>2020-01-30 08:10:49 UTC, "logicalSessionTimeoutMinutes"=>30, "connectionId"=>168, "minWireVersion"=>0, "maxWireVersion"=>8, "readOnly"=>false, "saslSupportedMechs"=>["SCRAM-SHA-256", "SCRAM-SHA-1"], "ok"=>1.0} average_round_trip_time=0.0028635040000000002> new=#<Mongo::Server:Description:0x47071377786500 config={"ismaster"=>true, "maxBsonObjectSize"=>16777216, "maxMessageSizeBytes"=>48000000, "maxWriteBatchSize"=>100000, "localTime"=>2020-01-30 08:10:52 UTC, "logicalSessionTimeoutMinutes"=>30, "connectionId"=>170, "minWireVersion"=>0, "maxWireVersion"=>8, "readOnly"=>false, "saslSupportedMechs"=>["SCRAM-SHA-256", "SCRAM-SHA-1"], "ok"=>1.0} average_round_trip_time=0.0024351632000000002>>
MONGODB | Server description for mongodb:27017 changed from 'standalone' to 'standalone'.
MONGODB | EVENT: #<TopologyChanged prev=Single[mongodb:27017] new=Single[mongodb:27017]>
MONGODB | Topology type 'Single' changed to type 'Single'.
MONGODB | [26] mongodb:27017 #3 | admin.saslStart | STARTED | {}
MONGODB | [26] mongodb:27017 | admin.saslStart | SUCCEEDED | 0.001s
MONGODB | [27] mongodb:27017 #3 | admin.saslContinue | STARTED | {}
MONGODB | [27] mongodb:27017 | admin.saslContinue | SUCCEEDED | 0.001s
MONGODB | [28] mongodb:27017 #3 | admin.saslContinue | STARTED | {}
MONGODB | [28] mongodb:27017 | admin.saslContinue | SUCCEEDED | 0.001s
MONGODB | [29] mongodb:27017 #3 | admin.endSessions | STARTED | {"endSessions"=>[{"id"=><BSON::Binary:0x47071403781940 type=uuid data=0xa448984090b24fab...>}]}
MONGODB | [29] mongodb:27017 | admin.endSessions | SUCCEEDED | 0.001s
root@a46ce56df74d:/usr/src/app# 

お!!

たぶん直っている。たぶん。

まとめ

Rails 6でMongoidやMongoDBを使い始めたらSegmentation Fault起きちゃって・・・ という方は concurrent-ruby を 1.1.6.pre1 以上にバージョン上げてみましょう。