環境
Rails 5.2.1.1
デプロイしたら Rails が出落ちした
ある日いつものように Rails アプリをデプロイすると、未定義の module を include しようとしていたことが原因で Rails がアプリケーションの読み込みに失敗し、uninitialized constant ... (NameError)
を吐いてクラッシュしてしまいました。
開発環境では動いたんだけど…
本番またはステージング環境では、開発環境と違って環境毎の設定ファイルに
config.eager_load = true
と書くことで Rails が起動時にアプリ全体を読み込むように設定すると思いますが、このときアプリ全体に少しでも読み込みに失敗するようなコードがあると Rails はクラッシュしてしまいます。
今回はデプロイ前に RuboCop の警告がないことを確認し、RSpec による単体テストを通してはいましたが、該当部分を通るテストケースがなかったために、読み込めないソースコードが存在することに気づくことができませんでした。
出落ちを未然に防いだ
単体テストが Rails アプリの全てのコードが読み込まれる程度にはしっかり書かれているのが理想ですが、完璧に網羅し続ける自信はありません。そこで、CI の Job に以下のコマンドを追加し、CI パイプライン内で Rails がアプリケーションの読み込みでエラーを起こさないことを確認するようにしました。
bundle exec rails runner Rails.application.eager_load!
これでデプロイ前に、少なくとも Rails が読み込みに失敗するようなコードが無いことを CI で保証できるようになりました。別のアプローチとして、以下のようにテスト時に環境変数で eager_load
を行うかを流し込めるようにするアプローチも見つけました1 が、テストケースの失敗とアプリケーションの読み込みの失敗を分けて把握したかったので、一旦上のような形に落ち着きました。
config.eager_load = ENV.fetch('EAGER_LOAD', '0') == '1'