AI エージェントの PR で GitHub Actions の無料枠が尽きた
きっかけは GitHub からの一通のメールでした。
[GitHub] You have used 90% of the Actions minutes included for the shinobiworks account
すぐにピンときました。GitHub Actions(GitHub の CI/CD の仕組み)の上限アラートが鳴ったのです。請求ページを開くと、1,917 / 2,000分と表示されていて、疑問に思ったのと同時に、このペースだと月末までの残り15日間、とても耐えられる状況ではありませんでした。
PR を減らして凌ぐことも一瞬考えましたが、それは開発と堅牢さを削る本末転倒だと気づき、課金して CI のジョブの重さを直しました。
PR が増えた月は、CI の分数も月の半ばで底を突いた
9月は PR の本数自体も増えました。3 リポジトリ合計の件数は次のとおりです。
- 7月: 86件
- 8月: 79件
- 9月(1〜17日): 155件(うち Dependabot 35件)
9月14日に Dependabot を有効にしたことに加え、サイトの移行と依存の更新で AI エージェント(コードの生成や PR の作成を任せている自動化された作業者)の PR が続いたことが理由です。
9月1〜15日の3 リポジトリ合計は、請求ページで1,917分でした(8月は1,189分)。自分でジョブの時間を足し上げた実測は2,072分で請求ページより8% 多く、判断は請求ページの値で行いました。
直近14日のワークフロー別の内訳は次のとおりです。
- Check: 826分
- Deploy: 342分
- Preview: 200分(9月14日に廃止)
- Backup: 170分
- Release: 70分
- Monitor: 32分
PR が続いた日は消費も跳ね、1日ごとの分数は次のとおりです。
- 9月14日: 542分
- 9月15日: 410分
料金体系を調べ、課金せずに済む道も検討した
GitHub Actions が無料で使える枠は、プランごとに次のように決まっています。
- Free: 月2,000分
- Pro / Team: 月3,000分
- Enterprise Cloud: 月50,000分
- 超過分は Linux の2-core ランナーが1分0.006ドル、Windows が0.010ドル、macOS が0.062ドル。共有ストレージは1GB あたり月0.25ドル
- public リポジトリは無料
- 2026年1月にホストランナーの単価が最大39% 下がった一方、全ワークフローに1分0.002ドルのクラウドプラットフォーム料金が加わった
支払い方法を登録していなければ、枠を使い切った時点で停止します。超過課金はされません。予算(budget)を設定すれば、75 / 90 / 100% の通知や、上限に達したときに停止する設定も選べます。
課金せずに済む道として、監視の間引き・ロックファイルを変えたときのデプロイ省略・Dependabot のメジャー更新のとりまとめ・public 化・セルフホストランナーを検討しましたが、どれも採りませんでした。質を下げる節約はしません。CI のジョブの束ね直しのような、どのみち良い変更だけを入れます。それでも足りなければ課金します。
月4ドルを後回しにしかけたが、Actions が止まればデプロイもバックアップも止まると気づいた
最初は「月4ドルを急ぐほどではない、残り83分を監視とバックアップに使い切ればいい」と考えました。ですが、止まるのは CI のジョブそのものです。デプロイもバックアップも一緒に止まります。無料で通用するのは、仕事を止めない範囲に限られます。今回はその範囲を越えていました。
月4ドルでGitHub Pro に上げ、3,000分の枠にしました。サイクルの途中で上げましたが、その場で1,917 / 3,000分の表示に切り替わりました。当月にそのまま反映されています。公式文書には「Upgrades are billed and applied immediately」とだけあり、含まれる分数が今のサイクルに入るかどうかまでは書かれていません。
副産物として、private リポジトリでルールセット(ブランチ保護)が使えるようになりました。Free では3 リポジトリとも有効化できません。エージェントに merge を任せる構成では、「赤い PR は merge できない」を仕組みで縛れる意味があります。
重いのは1回の重さと切り上げだったので、ジョブを束ね直した
PR が増えた分は、そのまま分数には効いていません。9月の Check は197回走り、そのうち全パッケージを検査した24回だけで568分(平均23分)を使い、残り173回は合計303分(平均1分)でした。全数検査になる条件は、ロックファイルを触ることです。Dependabot が出す PR はロックファイルを更新するため必ず全数検査になり、10回で112分を使っています。
重さのもう一つの正体は切り上げです。GitHub はジョブごとに使った分数を1分単位で切り上げます。
GitHub rounds the minutes and partial minutes each job uses up to the nearest whole minute.
1 ジョブの実行は60秒ほどです。内訳は準備と依存の取得に35秒、検査に16秒、ビルドに13秒です。この35秒の準備は、ジョブを増やすたびに丸ごと繰り返され、切り上げの1分にそのまま乗ります。壁時計の時間(run の開始から終了まで)とジョブの実行時間の合計、課金される分数はそれぞれ別物です。減らせるのは切り上げ後の課金分数だけです。
Check の matrix を「パッケージごと」の21 ジョブから「4 shard」に束ね直しました。ルートに183秒、サイトに67秒、共通パッケージに41秒の重みを付けました。重い処理から順にいちばん空いている担当へ回す LPT の貪欲法で、4つに割り振っています。全数検査になる run で比べると、次のように変わりました。
- 束ね直す前: 21 ジョブ、ジョブ実行時間の合計20分、課金32分
- 束ね直した後: 5 ジョブ、合計10.6分、課金13分
Backup も8 ジョブから1 ジョブに束ねました。課金は1日9分(実時間3.7分)から1日3分に減っています。ワークフローの設定だけを変える PR を merge したときは、アプリのデプロイが0件なので課金は1分で済みます。
全サイトのデプロイは11 ジョブ・実時間10.5分・課金16分で、1 サイトあたりのジョブ57〜72秒のうち35秒は Check と同じ準備です。この準備を束ねれば1回8分前後まで下がる見込みですが、こちらはまだ実施していません。
ジョブを束ねると効果が出るのは、切り上げの単位が1 ジョブ1分だからです。ジョブの数を減らすほど、切り上げで乗る端数の回数そのものが減ります。
束ね直しの続きと、課金を続けるかどうかはまだ判断の途中
- 全サイトのデプロイの束ね直しはまだ実施していない。見込みは1回8分前後
- GitHub Pro を続けるかどうかは、10月の実績(見込み1,300〜1,500分)で判断する
CI の分数を圧迫していたのは、PR が増えた分そのものではありません。ロックファイルを触る PR の全数検査と、ジョブごとの切り上げが効いていました。ジョブを束ねると、切り上げで乗る端数が減って課金の分数もまとめて減ります。それでも足りない分は、課金しないことの代償と比べて判断しました。代償とは、デプロイとバックアップが止まることです。