timeout-minutes の指定忘れを指摘する GitHub Actions を書いた
GitHub Actions の timeout-minutes
を明示的に指定しなかったことで minute quota 溶かしをやらかしたので作りました。
背景
パブリックなリポジトリで GitHub Actions を使っていると出くわすことはないかと思われますが、プライベートなリポジトリで GitHub Actions を書いていると timeout-minutes
を指定し損ねたジョブが延々と走り続けて minute quota (Team plan だと 3,000 分/月) を浪費してしまう 😭 みたいなとても悲しいできごとが発生することがまれにあります。
それというのも、timeout-minutes
を指定しなかった場合のデフォルトのタイムアウトが 360 分 (すなわち 6 時間) という長大な値となっているがために、下手こいて終わらないジョブを 9 回走らせてしまうだけでこの quota を綺麗サッパリ食べ尽くしてしまうという落とし穴1が GitHub Actions には存在するからですね2。
対策
こんな凄惨で悲しいできごとを二度と起こしてはいけない…! というわけで何某かの再発防止をしたいわけですが、生憎リポジトリや組織の単位で GitHub Actions ジョブのデフォルトタイムアウトを設定することが現時点ではできない模様です。したがって個別のジョブに timeout-minutes
を設定していく以外の対策が存在せず、その対策も人間が作業するとなるとどうしても「設定漏れ」のリスクが生じてしまいます。
そういうわけで、今回は (minute quota の浪費を防止するために minute quota を 1 分/回消費するという若干本末転倒感が否めないのですが…) timeout-minutes
が指定されていないジョブが存在したら fail させる GitHub Actions を作ってみたのでした。
使い方
例えば以下のようなワークフローを用意して、GitHub Actions を利用している各リポジトリの .github/workflows
ディレクトリに配置するだけです。Slack 通知が不要であれば - name: Slack notification
以降の行を削って構いません。
name: Enforce timeout-minutes
on: push
jobs:
enforce-timeout-minutes:
runs-on: ubuntu-latest
timeout-minutes: 2
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Enforce timeout-minutes
id: enforce-timeout-minutes
uses: komiya-atsushi/action-enforce-timeout-minutes@v1.0.0
- name: Slack notification
uses: rtCamp/action-slack-notify@v2
env:
SLACK_MESSAGE: ${{ steps.enforce-timeout-minutes.outputs.message }}
SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK_URL }}
if: ${{ failure() }}
余談: TypeScript での GitHub Actions 開発
GitHub Actions の開発は様々な手段があるのですが、今回は TypeScript を利用しました。
JavaScript であれば公式ドキュメントとして Creating a JavaScript action が存在するのでそれを少し参考にしつつ、TypeScript 固有の事情については typescript-action という公式 (?) のテンプレート的なリポジトリを大いに参考にしました。