Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Gradle×GitHub_ActionsでCI時間を約50%短縮 ジョブ分割の設計と落...

Sponsored · Your Podcast. Everywhere. Effortlessly. Share. Educate. Inspire. Entertain. You do you. We'll handle the rest.

Gradle×GitHub_ActionsでCI時間を約50%短縮 ジョブ分割の設計と落とし穴 / Cutting CI Time by ~50% with Gradle and GitHub Actions: Job-Splitting Design and Pitfalls

◆イベント名
JJUG CCC 2026 Spring
https://ccc2026spring.java-users.jp/
#jjug #jjug_ccc #jjug_ccc_m

◆発表タイトル
Gradle×GitHub ActionsでCI時間を約50%短縮 ジョブ分割の設計と落とし穴

◆登壇者
株式会社ラクス 楽楽明細開発部 開発3課 冨澤宝斗

Avatar for 冨澤宝斗

冨澤宝斗

May 29, 2026

More Decks by 冨澤宝斗

Other Decks in Technology

Transcript

  1. © RAKUS Co., Ltd. 1 Gradle×GitHub ActionsでCI時間を 約50%短縮 ジョブ分割の設計と落とし⽳ JJUG

    CCC 2026 Spring #jjug #jjug_ccc #jjug_ccc_m 2026/05/30 13:15 ~ 13:35 Room M 株式会社ラクス 楽楽明細開発部 開発3課 冨澤 宝⽃
  2. 3 ⽬次 1. なぜ今CIを速くするのか 2. テストの並列化 3. 並列化後に⾒えた問題 4. テストジョブ分割の再設計

    5. 分割後の各ジョブの軽量化 6. ワークフロー実⾏結果で判断するジョブ並列化 7. 結果⽐較とまとめ
  3. 7 なぜ今CIを速くするのか - 話すこと - ジョブ分割の設計 - ジョブ間の偏り解消 - ツール特性に合わせたGitの履歴取得

    - ワークフロー実⾏結果に基づく並列化判断 - 話さないこと - テストコード⾃体の⾼速化 - Gradle Build Cacheの最適化 - runner のスペック増強
  4. 10 テストの並列化 - 改善前(Step1) - unit-testジョブに全テストが集中 - lint → unit-test

    - unit-test: DB起動 → migration → テスト実施 → カバレッジ - 20分50秒 - 改善後(Step2) - Gradleのカスタムタスクで、testジョブを4分割 - GitHub Actionsのmatrix strategyで、4並列実⾏ - lint → 4並列testジョブ → jacoco-report - 10分40秒
  5. 14 ジョブ分割の再設計 【分割単位はパッケージで、判断基準は実⾏時間】 - ⽬的 - テストジョブの最⻑と最短の差を⼩さくする - ⽅針 -

    件数やパッケージ境界の綺麗さではなく、実⾏時間で判断する - 進め⽅ - 細かいパッケージ単位で実⾏時間を確認 - パッケージを移動し、ジョブごとのバランスを整える - 再測定し、ジョブ間の実⾏時間差分を⼩さくする
  6. 15 ジョブ分割の再設計 【パッケージ再配置の⼯夫】 事前準備 - どのテストがどのジョブで実⾏されたか整理 - 再配置前後で、同じテストが実⾏されているか確認 - 漏れが無い状態で再配置が可能に

    Gradleカスタムタスクの実装⽅針 - 専⽤ジョブ:対象パッケージを include - 残りを拾うジョブ:専⽤ジョブの対象パッケージを exclude
  7. 18 ジョブ分割の再設計 【結果:ジョブ間の実⾏時間差】 - 再分割前 - 215秒 - 再分割後 -

    最⼩で、15秒まで縮⼩(再分割直後の計測値) - 直近はテスト増加に伴い、平均約 50秒で推移 最⻑と最短の差が、約 4分の1 まで削減 並列化の効果は、ジョブ間の実⾏時間を均等化して初めて引き出せた
  8. 20 分割後の各ジョブの最適化 - 同じワークフロー内でも、ジョブごとに必要なGit情報が違う - checkoutのfetch-depthは最⼩化し、必要な参照は残す - 判断基準は、そのジョブが何をGitに期待しているか? ジョブ 必要なGit情報

    採用した設定 lint origin/main と 共通コミット fetch-depth: 50 + origin/main を明示 取得 test × 4 現在のソースコード fetch-depth: 1 jacoco-report 現在のソースコード + 成果 物 fetch-depth: 1
  9. 22 分割後の各ジョブの最適化 【lintジョブのfetch-depthの改善】 - fetch-depth: 0 によるGit履歴の完全取得をやめた - fetch-depth: 50

    にして、lintジョブを約 55秒 短縮 - 先端から50コミット分の履歴取得 ※完全履歴取得時のcheckoutは、ジョブ時間からの推定値 指標 履歴の完全取得時 最終形 lintジョブ(実測) 約 98秒 約 43秒 checkoutステップ 約 58秒(推定) 約 3秒(実測)
  10. 23 【fetch-depth: 1 でSpotlessが失敗した理由】 - 速くしたくて git fetch origin main

    --depth=1 に - ところが、これは取得結果を FETCH_HEAD に残すだけ - origin/main 参照を作らない - Spotlessの処理に必要な参照がCI上に無く、No such reference で失 敗に → ここで⼤事なのは、origin/main 参照が作られていないこと 分割後の各ジョブの最適化
  11. 24 【refspec で origin/main を作る】 - refspec で、取得した main を

    origin/main として保存 - checkoutでHEAD側、git fetchで origin/main 側を それぞれ先端から50コミット分取得 分割後の各ジョブの最適化
  12. 26 【判断基準:ジョブが必要とする前提条件で決める】 - そのジョブが何を前提に動くか確認する - Git履歴が必要なら、必要な参照(例: origin/main )と 共通コミットまで残す -

    成果物だけで完結する処理は、Git履歴から切り離す - fetch-depth は、ジョブごとの前提条件から決める → 動作に必要なGit情報だけを残し、履歴取得はできるだけ浅く 分割後の各ジョブの最適化
  13. 28 【変更前:lint → test の直列依存】 - 当時⼊れていた理由 - lintが落ちる変更に、重いtestジョブも4並列で回すのは無駄 -

    ただし、この考えが成⽴するのは lint が⼀定割合で落ちている前提 - 並列化の判断材料として、半年分の実⾏結果を確認した ワークフロー実⾏結果で判断するジョブ並列化
  14. 29 【lint失敗率を⾒て、並列化の判断】 - 半年で 1,856件の実⾏結果より、lint失敗は 26件 / 約 1.4% -

    純粋なlint単独失敗は、7件 / 約 0.4% - 残り 98.6% の実⾏は、毎回約 43秒の直列待ちをしていた 補⾜: Lefthookのpre-commmitにより、今後のlint失敗はさらに減る⾒込み → ジョブ依存関係は、実⾏結果で判断する ワークフロー実⾏結果で判断するジョブ並列化
  15. 32 【CI時間を約50%短縮し、その後もボトルネックを潰した】 ※直近の⽉平均は9分33秒。ただし依存関係更新など別要因も含む。 結果⽐較とまとめ 観点 改善内容 結果 テスト実行 matrix で分割

    20分50秒 → 10分40秒 ジョブ間の偏り パッケージ単位で再分割 約 215秒 → 約 15秒 (直近平均 約 50秒) lintジョブ Git履歴取得を最小化 約 98秒 → 約 43秒 ジョブ依存 needs: lint を削除 約 43秒の直列待ちを削除