🐧

GitHub Actions の実行履歴に基づいて自動で timeout-minutes を設定

2024/09/23に公開

GitHub Actions の timeout-minutes を自動で設定する ghatm という OSS を開発しています。

https://github.com/suzuki-shunsuke/ghatm

https://zenn.dev/shunsuke_suzuki/articles/github-actions-timeout-minutes

workflow の実行履歴を GitHub API で取得し job 毎に適切な timeout-minutes を設定する機能をリリースしたので紹介します。

https://github.com/suzuki-shunsuke/ghatm/releases/tag/v0.3.2

要約

  • ghatm v0.3.2 で GitHub Actions の実行履歴に基づいて自動で timeout-minutes を設定する機能をリリース
  • job ごとに適切な timeout-minutes を設定するのは大変なので、自動化できると便利
  • ghatm set -auto [-repo <owner>/<repo>] [-size <job のサンプリング数 | デフォルト 30>]
  • workflow_call 非対応など、まだまだ改善の余地あり

導入

元々 ghatm は timeout-minutes が設定されていない job に対しデフォルトで 30 を設定します。
この値は -t オプションで変更できますが、全 workflow 及び job で共通の値でした。
しかし適切な timeout-minutes は本来 job 毎に異なります。
多くの場合 30 で十分なはずですが、 job によってはもっと伸ばす必要があるでしょう。
全 job に同じ値を設定する場合一番時間のかかる job に合わせる必要がありますし、一番時間のかかる job がどのくらいかかるのか良く知らないと 60 や 90 といった長めの時間を設定することになります。
デフォルトは 360 に比べると 60 や 90 でもだいぶ良い方ではありますが、やはり job ごとにもう少し適切な値を設定したいものです。

この課題は大きな開発組織全体で ghatm を使って timeout-minutes を設定していくうえで障害になります。

そこで GitHub API で workflow の実行履歴を取得し、過去の実行履歴から適切な timeout-minutes を job 毎に算出できるようにしました。

適切な設定値を自動で設定

この機能を使うには対象リポジトリに対する actions:read を権限を持った GitHub Access Token が必要です。
環境変数 GITHUB_TOKEN または GHATM_GITHUB_TOKEN に access token を設定してください。

そして -auto option を設定して ghatm を実行します。

ghatm set -auto [-repo <owner>/<repo>] [-size 30]

こうすると各 job の 直近成功した (skip されたものは除外) 30 回の実行結果のうち最も長かった実行時間 + 10 が設定されます。
これは timeout に引っかからないよう結構安全側に倒しているつもりです。

サンプリングする job の回数が 30 だと足りない場合、 -size option でもっと増やすことも出来ますが、そうすると ghatm の実行時間と GitHub API call 数が増えるので注意してください。

-repo は workflow があるリポジトリのフルネームです。 GitHub API で workflow の実行履歴を取得するために必要です。
環境変数 $GITHUB_REPOSITORY で渡すことも可能です。

GitHub API のコール数

だいたいどのくらいの API が呼ばれるのか計算してみましょう。

  • list workflow runs by file name: 1 call あたり 100 workflow run を取得
  • list workflow jobs by run id: 1 call あたり 100 job を取得
    • 1 workflow run あたりの job 数が 100 を超えることはそうそうない
workflow 数 job 数 size job 実行率 job 成功率 API call 数
1 1 1 1 1 2 (1+1)
1 2 10 1 1 11 (1+10)
3 2 10 1 1 33 (3 * (1+10))
3 2 50 1 1 153 (3 * (1+50))
3 2 10 0.5 0.8 78 (3 * (1+ (10 / 0.5 / 0.8)))
3 2 30 0.5 0.8 228 (3 * (1+ (30 / 0.5 / 0.8)))

あくまで目安に過ぎませんが、だいたいこんな感じの計算式になりそうです。

workflow 数 * (1 + (size / job 実行率 / job 成功率))

job 数は関係なさそうですが、一番実行率 * 成功率が悪い job に引っ張られるはずです。

workflow_call の扱い

現状 -auto option による timeout-minutes の自動設定は Reusable Workflow に対応していません。

  • Reusable workflow の実行時間は呼び出し側の実行履歴を見ないとわからない
    • List workflow runs for a workflow API で Reusable workflow を指定しても workflow run のリストを取得できない
      $ gh api \
        -H "Accept: application/vnd.github+json" \
        -H "X-GitHub-Api-Version: 2022-11-28" \
        /repos/suzuki-shunsuke/ghatm/actions/workflows/wc-test.yaml/runs
      {
        "total_count": 0,
        "workflow_runs": []
      }
      
  • Reusable workflow は不特定多数から呼ばれている可能性がある
  • Reusable workflow の実行時間は呼び出し側に依存する場合がある

さいごに

以上、 ghatm の新機能を紹介しました。
まだこの機能は荒削りでもっとブラッシュアップしたいところではありますが、個人的に他にも色々やりたいことはあるので一旦ブログを書いてまた時間のあるときに改善していきたいと思います。
最初はもっと簡単かなと思ったのですが、実装を始めてみると結構考慮しないといけないことが多く中々難しいです。
個人的に workflow_call に対応できていないのは残念なのでなんとかしたいところです。

Discussion