GitHub Actions の無料枠2,000分を使い切った原因は、10月4日から失敗し続けていたCIだった

開発eurekapu-nuxt4

GitHub Actions の無料枠2,000分を使い切った原因は、10月4日から失敗し続けていたCIだった

GitHub から通知が来た。 今月の Actions 無料枠2,000分を、100%使い切ったという。 次のリセットは11月1日だ。

その直後から、Eurekapu の自動テストが3〜4秒で失敗する実行が出はじめた。 利用枠が原因かもしれない。 ただ、エラーの詳細も追加課金の設定も、まだ確認できていなかった。 再実行する前に、Actions のエラー表示と利用上限を確かめたほうがよさそうだと考えた。

同じセッションでは、直前まで「サブエージェントのプロンプトキャッシュは5分しか持たない(本体は1時間)」という話の真偽を、手元のログで確かめていた。 TTL が違うのは本当で、「5分を過ぎるとフルプライスがドカンと来る」は言い過ぎだった。 こちらは Claude Code のサブエージェントのキャッシュ寿命を測った記事 にまとめてある。 その記事をまとめるよう頼むのと一緒に、Actions の件も Claude Code に調べさせた。

3〜4秒で落ちる理由と、枠を減らした理由

3〜4秒で落ちる原因は、支出上限だと確定した。

ただし、それは枠を使い切ったあとの話である。 10月の枠を使い切った本当の原因は、CI が10月4日から失敗し続けていたことだった。

自分の見立ては、こうだった。 失敗が30個あり、そのうち長時間かかって失敗したのが28回ある。 ほぼこの28回が原因だろう。 毎回エラーが出ていて困っていたので、そのまま修正を頼んだ。

調べさせると、失敗の原因は1つではなかった。 主因はカード枚数のテストで、ほかにも2種類の失敗が混ざっていた。

時間の使い方にも偏りがあった。 ユニットテストの所要時間の89%(23.5分)を、excelSceneBookRegression.test.ts の1本が占めていた。

gh に user スコープを足す

並行して、自分のターミナルから次のコマンドを打った。

gh auth refresh -h github.com -s user

コマンドは120秒のタイムアウトで打ち切られ、バックグラウンドに回された。 コードを入力すると、アクセスできた。 認証が通ってから、支出上限の確認と、直したテストの手元での実行を Claude Code に同時に進めさせた。

3つの原因の修正と push

CI が毎回落ちていた原因を3つとも直させ、コミットして push した(6e93d9e5)。 このとき、別のセッションが sim-modules のファイルをステージしていた。 それは巻き込まず、パスを指定して自分の4ファイルだけをコミットさせた。

ただし、GitHub 上の CI で通るかはまだ確かめられていない。 Actions は枠切れで、11月1日まで動かないからだ。

回帰テストを Actions で回すか

回帰テストは、ローカルで流してもタイムアウトしていた。 それなら GitHub Actions で回さないほうがいいのではないか、と自分から言った。

返ってきたのは、その対応はもう済んでいる、という答えだった。 6e93d9e5 で、CI のユニットテストに SCENE_TARGETS=none が付いていた。 GitHub Actions では、画面再現の回帰テスト2本(excelSceneRegression と excelSceneBookRegression)はもう流れない。 この2本が飛ばされることも、Claude Code が手元で SCENE_TARGETS=none を付けて確かめてあった。

手元で全区間を一度に流すとタイムアウトするのは、excelSceneBookRegression だけで23分かかるためだ。 台本やエンジンを直したときは、変更が効く区間だけを手元で流す。

# CI 側:画面再現の回帰テスト2本を飛ばす
SCENE_TARGETS=none
# 手元:変更が効く区間だけを流す
node scripts/test-scene-regression.mjs --changed

自分が言い出したときには、同じ線引きがもうコミットに入っていた。

別セッションの差分がターミナルに混じる

コミットの話の途中で、ターミナルに別セッションの差分が混じって表示されていた。 表示だけでなく、セッションログにも混じっているのではないか。 もしそれがコンテキストに入っているなら、完全にバグである。 そう考えて、このセッションのログファイルを見に行かせた。

ログには記録されていた。 ただし、AI に渡るコンテキストには入っていなかった。

最初は「ログには記録がなく、ターミナルの表示だけの問題」と受け取り、不思議だと聞き返した。 答えは逆で、ログには記録されているので、ターミナルの表示だけの問題ではない、とのことだった。 コンテキストに入っていないことは、確認済みだという。

積み残しの片付けとメモリの逼迫

積み残しを尋ねると、3件残っていた。 1件目は、キャッシュの記事がまだ未コミットで、公開されていないことだった。

記事をコミットさせ(4628b1e5)、続けて11月1日のタスクの登録へ進めさせた。 そのあと、デプロイ前の検査に入った。 未公開の別記事を一時的に退避し、未公開記事へのリンクを文字表記に直して、検査を流し直した。 検査はすべて通り、デプロイは11時39分に始まった。 見込みは12〜20分で、プリレンダー(3,117ページ)まで進んだ。

ここで、手元のメモリがパンパンになった。 一旦止めてほしいと頼んだ。

デプロイはプリレンダーの途中で止まり、本番にはまだ何もアップロードされていなかった。 退避していた記事も元に戻した。

メモリの使い道を調べさせると、一番大きいのは eurekapu-nuxt4 の開発サーバー(ポート3200)だった。

使っているものメモリ
開発サーバーの下にぶら下がる workerd 143個約6GB
開発サーバー本体1.9GB
合計約8GB

振り返り

  • テストが3〜4秒で落ちる失敗と、枠を減らした失敗は別物だった。前者の原因は支出上限で、後者は10月4日から失敗し続けていた CI だった
  • ローカルでもタイムアウトする回帰テストは、CI から外した。CI では SCENE_TARGETS=none で飛ばし、手元では --changed で変更が効く区間だけを流す

直した 6e93d9e5 が GitHub 上で通るかどうかは、11月1日に枠が戻るまで分からない。

#GitHub Actions#CI#回帰テスト#gh CLI#Claude Code