AWS CodeBuildプロジェクトで「自動再試行の上限」を設定できるようになりました。
https://docs.aws.amazon.com/codebuild/latest/userguide/auto-retry-build.html
この記事の方法は、その設定ができない場合のみ採用をご検討ください。
この記事では、AWS CodeBuildで失敗したビルドを自動的に再試行する例をご紹介します。実務で必要になり、LambdaとEventBridgeで実装したものです。
なお、実務で適用したビルドプロジェクトには、下記のような特徴があります。
- 毎日早朝にビルドが始まるようスケジューリングしている
- 開始から完了まで数十分かかる
- たまに失敗するが、根本的な修正はすぐには難しい
- 連続して失敗することもある
- 再試行が翌営業日になっても大きな問題はない
以下、上記の前提を念頭にご覧ください。
EventBridgeで失敗を検知する
さて、まずは、CodeBuildのビルド失敗をEventBridgeで検知します。
EventBridgeルールで、イベントパターンを下記のように指定すると、ビルドプロジェクト project-name
のビルド失敗が検知できます。
{
"source": ["aws.codebuild"],
"detail-type": ["CodeBuild Build State Change"],
"detail": {
"build-status": ["FAILED"],
"project-name": ["project-name"]
}
}
イベントパターンの詳細については、公式ドキュメントをご参照ください。
Lambdaで再試行する
続いて、EventBridgeルールのターゲットとなるLambda関数を作成します。下記がコード例です。
import os
import boto3
SUCCESS_CHECK_WINDOW = int(os.getenv("SUCCESS_CHECK_WINDOW", 5))
def lambda_handler(event, context):
project_name = event["detail"]["project-name"]
# リトライ条件:
# 1. 直近のビルドに失敗していること
# 2. 直近 SUCCESS_CHECK_WINDOW 件のビルドのうち、少なくとも1件に成功していること
codebuild = boto3.client("codebuild")
response = codebuild.list_builds_for_project(projectName=project_name)
builds_detail = codebuild.batch_get_builds(
ids=response["ids"][:SUCCESS_CHECK_WINDOW]
)
if builds_detail["builds"][0]["buildStatus"] == "FAILED" and any(
b["buildStatus"] == "SUCCEEDED" for b in builds_detail["builds"]
):
response = codebuild.retry_build(id=builds_detail["builds"][0]["id"])
print(
f"Rebuild initiated for project '{project_name}' "
f"with ID '{response['build']['id']}'"
)
この例では、Lambda関数が同時に複数実行されても1件の再試行に抑えるため、直近のビルドに失敗していること
をチェックしています。
また、ビルド失敗の無限ループを避けるため、直近 SUCCESS_CHECK_WINDOW 件のビルドのうち、少なくとも1件に成功していること
もチェックしています。SUCCESS_CHECK_WINDOW
は環境変数です。
Lambda関数の実行ロールには、CodeBuildアクションの許可が必要です。
{
"Version": "2012-10-17",
"Statement": [
{
"Action": [
"codebuild:BatchGetBuilds",
"codebuild:ListBuildsForProject",
"codebuild:RetryBuild"
],
"Effect": "Allow",
"Resource": "arn:aws:codebuild:{Region}:{Account ID}:project/project-name"
}
]
}
このLambda関数を、EventBridgeルールのターゲットとして指定すれば、失敗ビルドが自動的に再試行されるようになります。
実務では、ビルド状況をSlackに通知しています。
https://docs.aws.amazon.com/ja_jp/codebuild/latest/userguide/notification-rule-create.html
これにより、もしLambdaでの再試行がうまくいかなくても、翌営業日には気づけ、人力で再試行できます。
料金はほとんどかからない
これらを実装するとLambdaの料金が発生します。ただし、微々たるものなので、ほとんどの場合は無視できるでしょう。
おわりに
この記事では、CodeBuildの失敗ビルドを自動的に再試行するために、EventBridgeとLambdaを利用する例をご紹介しました。
実務では、これまで人力で再試行していた手間が省け、担当者に喜んでいただけました。導入から2ヶ月あまりで、人力での再試行は数回だけです。
このように「ちょっとの手間を我慢して担当者が人力対応しているタスク」は探せば色々あると思います。EventBridgeやLambdaをうまく使えば、そのようなタスクが自動化できるかもしれません。
ちなみに、記載したLambda関数のコードは、OpenAIのgpt-4モデルとチャットしながら作ったものでした。関数の目的を伝えたたけで、ほぼ意図どおりのコードが出力されてしまいました。すごい時代ですね。