Gradle×GitHub_ActionsでCI時間を約50%短縮 ジョブ分割の設計と落とし穴 / Cutting CI Time by ~50% with Gradle and GitHub Actions: Job-Splitting Design and Pitfalls
by
冨澤宝斗
×
Copy
Open
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
Slide 1
Slide 1 text
© 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課 冨澤 宝⽃
Slide 2
Slide 2 text
2 ⾃⼰紹介 冨澤 宝⽃(Tomizawa Takato) 2022年 新卒⼊社 楽楽明細開発部 開発3課 楽楽電⼦保存→楽楽債権管理のバックエンドを担当 沖縄出⾝で、バスケとK-POPが好きです
Slide 3
Slide 3 text
3 ⽬次 1. なぜ今CIを速くするのか 2. テストの並列化 3. 並列化後に⾒えた問題 4. テストジョブ分割の再設計 5. 分割後の各ジョブの軽量化 6. ワークフロー実⾏結果で判断するジョブ並列化 7. 結果⽐較とまとめ
Slide 4
Slide 4 text
© RAKUS Co., Ltd. 4 なぜ今CIを速くするのか
Slide 5
Slide 5 text
5 なぜ今CIを速くするのか コーディングエージェントにより、実装‧修正サイクルの⾼速化 ⼀⽅PRごとにCIを待つ時間は、意識的に改善しない限り速くならない 実装が速くなるほど、CI待ち時間が開発サイクルのボトルネックになる より⾼速な開発やプロダクトの仮説検証に向けて、 CIの実⾏時間削減が必要だと判断
Slide 6
Slide 6 text
6 なぜ今CIを速くするのか 【今⽇のゴール】 GradleとGitHub Actionsを使ってCI時間を約50%短縮した事例から、 以下の2つを持ち帰っていただく 1. ジョブ分割の設計指針 2. 最適化の判断基準
Slide 7
Slide 7 text
7 なぜ今CIを速くするのか - 話すこと - ジョブ分割の設計 - ジョブ間の偏り解消 - ツール特性に合わせたGitの履歴取得 - ワークフロー実⾏結果に基づく並列化判断 - 話さないこと - テストコード⾃体の⾼速化 - Gradle Build Cacheの最適化 - runner のスペック増強
Slide 8
Slide 8 text
8 GitHub Actions テストワークフローの変遷 ※本セッションでのCI時間は、 こちらのテストワークフローの成功時の 平均完了時間を指します
Slide 9
Slide 9 text
© RAKUS Co., Ltd. 9 テストの並列化
Slide 10
Slide 10 text
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秒
Slide 11
Slide 11 text
© RAKUS Co., Ltd. 11 並列化後に⾒えた問題
Slide 12
Slide 12 text
12 並列化後に⾒えた問題 【ジョブ間の実⾏時間の偏り】 最短と最⻑の差:215秒 すべてのジョブが完了するまで 次のジョブに進めない つまり、⼀番遅いジョブが、 CI全体の完了時間を決める なので、ジョブ分割を ⾒直す必要があった
Slide 13
Slide 13 text
© RAKUS Co., Ltd. 13 テストジョブ分割の再設計
Slide 14
Slide 14 text
14 ジョブ分割の再設計 【分割単位はパッケージで、判断基準は実⾏時間】 - ⽬的 - テストジョブの最⻑と最短の差を⼩さくする - ⽅針 - 件数やパッケージ境界の綺麗さではなく、実⾏時間で判断する - 進め⽅ - 細かいパッケージ単位で実⾏時間を確認 - パッケージを移動し、ジョブごとのバランスを整える - 再測定し、ジョブ間の実⾏時間差分を⼩さくする
Slide 15
Slide 15 text
15 ジョブ分割の再設計 【パッケージ再配置の⼯夫】 事前準備 - どのテストがどのジョブで実⾏されたか整理 - 再配置前後で、同じテストが実⾏されているか確認 - 漏れが無い状態で再配置が可能に Gradleカスタムタスクの実装⽅針 - 専⽤ジョブ:対象パッケージを include - 残りを拾うジョブ:専⽤ジョブの対象パッケージを exclude
Slide 16
Slide 16 text
16 ジョブ分割の再設計
Slide 17
Slide 17 text
17 ジョブ分割の再設計
Slide 18
Slide 18 text
18 ジョブ分割の再設計 【結果:ジョブ間の実⾏時間差】 - 再分割前 - 215秒 - 再分割後 - 最⼩で、15秒まで縮⼩(再分割直後の計測値) - 直近はテスト増加に伴い、平均約 50秒で推移 最⻑と最短の差が、約 4分の1 まで削減 並列化の効果は、ジョブ間の実⾏時間を均等化して初めて引き出せた
Slide 19
Slide 19 text
© RAKUS Co., Ltd. 19 分割後の各ジョブの最適化
Slide 20
Slide 20 text
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
Slide 21
Slide 21 text
21 分割後の各ジョブの最適化
Slide 22
Slide 22 text
22 分割後の各ジョブの最適化 【lintジョブのfetch-depthの改善】 - fetch-depth: 0 によるGit履歴の完全取得をやめた - fetch-depth: 50 にして、lintジョブを約 55秒 短縮 - 先端から50コミット分の履歴取得 ※完全履歴取得時のcheckoutは、ジョブ時間からの推定値 指標 履歴の完全取得時 最終形 lintジョブ(実測) 約 98秒 約 43秒 checkoutステップ 約 58秒(推定) 約 3秒(実測)
Slide 23
Slide 23 text
23 【fetch-depth: 1 でSpotlessが失敗した理由】 - 速くしたくて git fetch origin main --depth=1 に - ところが、これは取得結果を FETCH_HEAD に残すだけ - origin/main 参照を作らない - Spotlessの処理に必要な参照がCI上に無く、No such reference で失 敗に → ここで⼤事なのは、origin/main 参照が作られていないこと 分割後の各ジョブの最適化
Slide 24
Slide 24 text
24 【refspec で origin/main を作る】 - refspec で、取得した main を origin/main として保存 - checkoutでHEAD側、git fetchで origin/main 側を それぞれ先端から50コミット分取得 分割後の各ジョブの最適化
Slide 25
Slide 25 text
25 【履歴が不要なジョブは浅くする】 - test ジョブは、現在のソースコードがあれば実⾏可能 - jacoco-report ジョブは、現在のソースコードとテスト結果の成果物か らレポート⽣成 - どちらもGit履歴や origin/main との⽐較は不要 分割後の各ジョブの最適化
Slide 26
Slide 26 text
26 【判断基準:ジョブが必要とする前提条件で決める】 - そのジョブが何を前提に動くか確認する - Git履歴が必要なら、必要な参照(例: origin/main )と 共通コミットまで残す - 成果物だけで完結する処理は、Git履歴から切り離す - fetch-depth は、ジョブごとの前提条件から決める → 動作に必要なGit情報だけを残し、履歴取得はできるだけ浅く 分割後の各ジョブの最適化
Slide 27
Slide 27 text
© RAKUS Co., Ltd. 27 ワークフロー実⾏結果で判断する ジョブ並列化
Slide 28
Slide 28 text
28 【変更前:lint → test の直列依存】 - 当時⼊れていた理由 - lintが落ちる変更に、重いtestジョブも4並列で回すのは無駄 - ただし、この考えが成⽴するのは lint が⼀定割合で落ちている前提 - 並列化の判断材料として、半年分の実⾏結果を確認した ワークフロー実⾏結果で判断するジョブ並列化
Slide 29
Slide 29 text
29 【lint失敗率を⾒て、並列化の判断】 - 半年で 1,856件の実⾏結果より、lint失敗は 26件 / 約 1.4% - 純粋なlint単独失敗は、7件 / 約 0.4% - 残り 98.6% の実⾏は、毎回約 43秒の直列待ちをしていた 補⾜: Lefthookのpre-commmitにより、今後のlint失敗はさらに減る⾒込み → ジョブ依存関係は、実⾏結果で判断する ワークフロー実⾏結果で判断するジョブ並列化
Slide 30
Slide 30 text
30 GitHub Actions テストワークフローの変遷
Slide 31
Slide 31 text
© RAKUS Co., Ltd. 31 結果⽐較とまとめ
Slide 32
Slide 32 text
32 【CI時間を約50%短縮し、その後もボトルネックを潰した】 ※直近の⽉平均は9分33秒。ただし依存関係更新など別要因も含む。 結果⽐較とまとめ 観点 改善内容 結果 テスト実行 matrix で分割 20分50秒 → 10分40秒 ジョブ間の偏り パッケージ単位で再分割 約 215秒 → 約 15秒 (直近平均 約 50秒) lintジョブ Git履歴取得を最小化 約 98秒 → 約 43秒 ジョブ依存 needs: lint を削除 約 43秒の直列待ちを削除
Slide 33
Slide 33 text
【持ち帰って欲しい設計指針と判断基準】 - ジョブ分割の設計指針 - 並列化は「分けて終わり」ではない - 最適化の判断基準 - 設定は「⼀律」ではなく「処理の前提条件」から考える - 依存は「過去の判断」ではなく「データ」で⾒直す 33 結果⽐較とまとめ
Slide 34
Slide 34 text
ご清聴ありがとうございました! 以下のアンケートにご回答をお願いいたします 34 JJUG CCC 2026 Spring 全体アンケート JJUG CCC 2026 Spring セッションアンケート