こんにちは、サーバーサイドエンジニアのmitaniです。先月、B/43を構成するシステムのうち、3つのRailsリポジトリの7.1バージョンアップが完了しました!
大きな躓きポイントはなかったのですが、参考までに手順やRails 7.1の内容を紹介しようと思います。
B/43のアーキテクチャ
B/43は、上の図のように複数のサービスから構成されています。そのうちRailsで作られているサービスが3つあります(core-api / auth-api / aml-api)。バージョンアップする際には3つまとめて行う運用をとっているため、今回も3つバージョンアップしました。
各リポジトリは全てDocker化されています。各リポジトリのDockerfileは、共通してruby等をインストールしているベースイメージをFROMに指定して作成しています。そのため、rubyのバージョンアップの際にはベースイメージの変更だけで済むのですが、今回のRailsのバージョンアップはそれぞれのリポジトリで行う必要があり、順に行っていきました。
補足
- バージョンアップ前はRails 7.0.8で動いており、今回は7.1.3までバージョンアップしました
- 各リポジトリで使っているgemは、dependabotを使って日々最新のバージョンにアップデートしています。そのため、今回のRailsバージョンアップに伴ってアップデートが必要なgemはありませんでした
- 3つのリポジトリは全てapi modeなのでフロントエンドのコードはありません
バージョンアップ
バージョンアップするリポジトリ順序
B/43は複数のサービスから構成されていますが、コードベースのほとんどはcore-apiに集約されています。aml-api / auth-apiはcore-apiに比べるとかなり小さめなサービスになっています。
rails statsの紹介
参考までにcore-apiとauth-apiのrails statsを紹介します。
core-api
Name | Lines | LOC | Classes | Methods | M/C | LOC/M |
---|---|---|---|---|---|---|
Controllers | 14135 | 10955 | 250 | 1182 | 4 | 7 |
Jobs | 887 | 614 | 42 | 64 | 1 | 7 |
Models | 43568 | 31643 | 830 | 3097 | 3 | 8 |
Mailers | 775 | 543 | 29 | 79 | 2 | 4 |
Views | 4319 | 3744 | 0 | 0 | 0 | 0 |
Libraries | 4728 | 3546 | 9 | 67 | 7 | 50 |
Total | 68412 | 51045 | 1160 | 4489 | 3 | 9 |
auth-api
Name | Lines | LOC | Classes | Methods | M/C | LOC/M |
---|---|---|---|---|---|---|
Controllers | 250 | 187 | 6 | 21 | 3 | 6 |
Jobs | 9 | 2 | 1 | 0 | 0 | 0 |
Models | 128 | 92 | 3 | 12 | 4 | 5 |
Libraries | 52 | 40 | 1 | 5 | 5 | 6 |
Total | 439 | 321 | 11 | 38 | 3 | 6 |
上記のように、コントローラーのクラス数で見るとcore-apiが250に対してauth-apiが6つと、機能の差がわかると思います。aml-apiも大体同じ感じです。
できるだけ小さいリポジトリから対応した方がバージョンアップの影響範囲が少ないだろうという理由で、 はじめにauth-apiとaml-apiを同時にバージョンアップ、終わったらcore-apiを続いてバージョンアップする順で行いました。
実施手順
Rails アップグレードガイドにあるアップグレード手順の通り、以下の手順で行っています。
Railsのバージョンアップ
- Gemfileファイル内のRailsバージョン番号を変更し、
bundle update rails
を実行する bundle exec rails app:update
を実行する- 対話式なので一旦全て yes (overwritesする)で実行する
- コンフリクトが起きた箇所を一箇所ずつ眺めて解消する
config/initializers/new_framework_defaults_7_1.rb
はそのまま- この状態で1回目のリリース
7.1からの設定変更部分の対応
config/initializers/new_framework_defaults_7_1.rb
の内容を見て、簡単そうな設定からコメントインし動作確認- 動作確認ができたらリリース
- 大体1つのリポジトリあたり5個くらいのPRに分けて全ての設定を対応しました
config.load_defaultsの変更
config/application.rb
のconfig.load_defaults
を7.1に変更config/initializers/new_framework_defaults_7_1.rb
を削除- 上記をリリースして完全終了 👏
上記手順でリリース後の障害0で無事バージョンアップを完了させることができました 👏
社内での進め方
スマートバンクでは基本サーバーサイドエンジニアは全員機能開発のPJに参加しているため、Railsのバージョンアップのようなタスクを専任で行うチームはいません。代わりに、優先度が高い横断的なタスクが生まれた時には有志が集まり、水曜日の17:00から2時間ほど課題に取り組む時間を取って対応をしています。
今回のRailsバージョンアップも同じように、その時に集まれた4~5人で作業を分担しながら進めました。
初めはaml-api / auth-apiで上記のRailsのバージョンアップの手順を行ってリリースするところまでを1日で行い、翌週からはnew_framework_defaults_7_1.rb
の内容を読み解いて特別な対応が必要な箇所の洗い出しを行いました。
上記のように調べたことをNotionに各自がまとめていき、問題なさそうなものをいくつかグルーピングして順にリリースしていきました。
Rails 7.1の推しポイント
特に面白みのない手順紹介になってしまったので、最後に個人的なRails 7.1の推しポイントを紹介します。折を見て本番投入していきたい!
config.i18n.raise_on_missing_translations = true
I18n.t("missing.key")
のように存在しないキーを指定したときに、Rails 7.1以降はraiseしてくれるようになりました。
B/43では、サーバーからアプリに返すメッセージをI18n APIで定義するようにしているのですが、使わなくなった機能のメッセージを削除する際、「ほんとに削除して大丈夫なのか…??」と不安になることがありました。この設定で例外が発生してくれるとCIで異常を検知しやすくなるので嬉しいですね。
テーブルのindex名が長い場合の自動生成
外部キーを貼ったらテーブル名が長すぎてindex名の長さがDBの制約に引っかかることがよくありました。そうした際にindex名のルールをコーディング規約として定義していたのですが、あまり生産的ではなく面倒と感じてたところ、Rails 7.1からは自動生成してくれることとなったので歓喜です。
ActiveRecord::Base.normalizesが追加
これまで値の正規化をbefore_validationで書いていた人もいるかもしれませんが、normalizes
が追加されたことで適正な場所で適正な処理を実装できるようになりましたね!
大量のジョブを一度にエンキューするperform_all_laterが追加
B/43ではメールやPushの一括配信をrakeで実装し、内部で非同期ワーカーに1件ずつ各ユーザーへの処理を詰めるような実装をしているものがいくつかあります。こういうタスクの実行時間は長くなりがちなので、perform_all_later
で処理が早くなるかは楽しみです。
Trilogy用のアダプタが導入
mysql2に変わるデータベースクライアントとして注目されるTrilogyですが、アダプターが正式に導入されました。ネットの記事などでは実際に導入して高速化した!というものも見るので、B/43でも導入してみたいです。
汎用の非同期クエリを対象とするActive Record API
クエリ実行を非同期でやってくれるAPIが追加されました。どういうユースケースで使えるのかはまだまだ見えてませんが、実行時間が長いバッチはB/43にも多々あるので、それらの改善になるかも…!!??
以上、Rails 7.1にバージョンアップしましたレポートでした。次のRails 8が楽しみですね!!
スマートバンクのエンジニア組織に興味がある方はこちらもご覧ください!カジュアル面談もお待ちしております!