前提
今の案件に参画当時、Railsのローカルの開発環境でrails consoleを実行してActive RecordでのDB操作を試みたり、rails runnerでDB操作を伴うコマンドを実行したりすると以下のようなエラーが発生するという事象に遭遇しました。
※ rails serverは正常に実行できました。
エラー
objc[8247]: +[Swift.__SharedStringStorage initialize] may have been in progress in another thread when fork() was called. objc[8247]: +[Swift.__SharedStringStorage initialize] may have been in progress in another thread when fork() was called. We cannot safely call it or ignore it in the fork() child process. Crashing instead. Set a breakpoint on objc_initializeAfterForkError to debug.
案件内では既知の事象で対応が確立されており、以下のようにrails console実行時に先頭にDISABLE_SPRING=trueを付与することで解消できました。
DISABLE_SPRING=true bundle exec rails console
この事象はRailの公式リポジトリ上でもissue化されています。
ただ自分の中で完全におまじない化しているので、この機会にこのオプションの意味をある程度理解してみたいと思います。
環境
DISABLE_SPRING=true の意味
DISABLE_SPRING=true は直接的にはSpringというライブラリを無効化しています。
Springについては、以下のREADMEの説明の通り、開発環境での性能を改善してくれるライブラリのようです。
Spring is a Rails application preloader. It speeds up development by keeping your application running in the background, so you don't need to boot it every time you run a test, rake task or migration.
※ Rails7以降はSpringはデフォルトではインストールされない
SpringはRails7以降はデフォルトではインストールされなくなっています。従って、Rails7以降を使っている場合は明示的にSpringを使っている環境が対象になります。
Spring is no longer on by default, as faster computers have made it less relevant on anything but the largest applications.
なぜSpringを使うと冒頭のエラーが発生するのか
上記のissueのやり取りをAIに解説してもらったところ、ざっくり以下のような感じのようです。
そのため、issueではOBJC_DISABLE_INITIALIZE_FORK_SAFETY=YESとしてMacのセキュリティ設定の方を変更する対応も提案されています。 (私の環境では機能しませんでした)
加えて、Springが使われるのはconsole, runner, generate, destroy, test のコマンドのみで、server は対象ではないそうです。
たしかにrails consoleを実行した場合は、Running via Spring preloader in process xxxというメッセージが表示されますが、rails serverでは表示されません。
rails serverでは発生しなかった理由が理解できます。
まとめ
おまじないだったDISABLE_SPRING=trueの意味が多少は理解できました。
- 冒頭のエラーの原因はSpringという開発環境の性能向上用のライブラリがMac OSと相性が悪いことに起因
DISABLE_SPRING=trueはSpringを無効化している