月に1000回のビルド実行、そのどれにもお金はかかっていません ⚙️
まず訂正です。この記事の最初のバージョンでは、GitHubのビルド時間を使い切ってしまい、そのせいでProアカウントにアップグレードせざるをえなかった、と書いていました。それは間違いでした。ドキュメントを一目見ればわかったことです。公開リポジトリでは、GitHubのビルド時間は無料です。アーティファクトもキャッシュもです。うちのリポジトリは5月末から公開されているので、1分もお金を払ったことはありませんし、これからも払いません。こっそり文章を直すのではなく、書き直して、実際に測定で何がわかったのかをお伝えしたいと思います。それは、間違ったバージョンよりずっとおもしろい話になりました。
まず推測、それから確認。きっかけは、ある夜のことでした。完成したプルリクエストがブラウザに表示されているのに、チェックがひとつも動かなかったのです。緑のチェックマークもなく、ただの沈黙。私たちはいちばんありそうな説明、「上限に達した」に飛びついて、Proアカウントを取りました。そのあとはすべて動いたので、その説が正しいように見えました。でもそうではありませんでした。沈黙の原因は別のところにありました(そのときGitHubがメインブランチときれいにマージできないプルリクエストは、チェックを何も始めません)。その後、すべての実行の課金データを調べました。どの実行でも、どのOSでも、答えは同じです。課金対象の時間は0ミリ秒。サブスクリプションでプラットフォームを応援するのはまったく悪くありませんが、このリポジトリの説明としては成り立ちません。
本当のこと:しくみが大きくなりました。プルリクエストが出るたびに、小さな工場が動き出します。サーバー全体のビルドとテストスイートの実行、リンターとコード解析によるチェック、CodeQLによるセキュリティホール探し、そしてゲームサーバー、ポータル、WorldHost、AIバックエンドのDockerイメージの作成です。リリースでは、さらにクライアントのWindows、Linux、macOS向けビルドと、ブラウザゲーム用のWebGL版が加わります。5月末からの合計は1,723回のビルド実行、そのうち7月だけで1,092回で、4週間で131件のプルリクエストがマージされました。そして、最近の急増は本当にAIと関係があります😉。このプロジェクトは100%AIの助けを借りて開発されていて、上位のサブスクリプションにしたことで、単純に並行して起こることが増えたのです。ただし、ここでの通貨はお金ではなく、待ち時間です。
待ち時間はどこに行くのか。8日間で測ると、通常のチェック実行(CI)が379分、CodeQLのセキュリティ解析が230分、リリースビルドが126分、残りは細かいものです。リリース1回で約110分の計算時間がかかり、その内訳はWebGL(31.6)、Dockerイメージ(19.4)、macOS(13.7)、Linux(13.7)、大きなテストゲート(12.1)、Windows(10.9)、パッケージング(7.2)です。これが、「できた」から「みなさんがインストールできる」までの時間です。
そして、本当に足りないのがこれ:キャッシュ。ビルドが毎回ゼロから始まらないように、GitHubは途中の結果を保存します。そのための容量は、公開かどうかにかかわらずリポジトリごとに10GBです。うちには現在、63個のエントリで5.3GBが入っています。問題は配分で、およそ3分の2がDockerの中間レイヤーで、実行のたびに再アップロードされ、いちばん役に立つはずのものを押し出してしまっているのです。これが本当のボトルネックで、どんなサブスクリプションでも買って抜け出すことはできません。
いちばんうれしい発見は、本物のバグでした。ビルドのとき、Unityは巨大な中間フォルダ(Library)をつくり、それを再利用すると数分の節約になります。測ってみてわかったのは、Windows、Linux、macOSでは、そのフォルダが一度も保存されていなかったということです。ビルドはまじめに復元しようとしていたのに、だれも書き込んでいなかったのです。そしてWindowsのビルドだけが、プラットフォームの印のないキャッシュキーを持っていました。その結果、1.7GBのWebGLの中間状態をダウンロードしてしまい、Unityは律儀にそれを捨ててから、すべてを再インポートしていました。ログにははっきり出ています。アセットのインポートが、温まった状態なら85秒のところ257秒。キーにたった1語が足りなかったせいで、リリースごとに9分近くも無駄にしていたのです。
ほかにも見つかったこと。うちのテストスイートは、出荷するコミットごとに3回動きます(プルリクエストで、マージ後に、そしてリリースで)。CodeQLは、必須のチェックでもないのに、プルリクエストのたびに3つの言語を調べています。.NETパッケージ用のキャッシュは、まったくありません。1つのアーキテクチャ向けにしかビルドしないのに、ほかのプロセッサ向けのエミュレーターがセットアップされています。そして7.4GBの古いビルド成果物が、デフォルトの90日間の保持で置きっぱなしです。どれも大げさな話ではありませんが、合わせると、人生のかなりの時間になります。
教訓は、サーバーが教えてくれたものと同じです。以前、使われているメモリの半分が、ゲームではなくDockerと監視に使われていることを測定でつきとめました。今回はさらに恥ずかしいことに、存在しない請求書を思い込んで、確かめる前にお金を払っていたのです。推測せずに測る。この言葉は、本当に身につくまでは当てはまりつづけるようです。整理の作業は計画してありますが、まだできていません。実行したら、何が得られたかをお伝えします。🚀
コメント