Step Functionsを使用したバッチジョブの制御

AWS

背景

CodeBuildで作成したバッチ1つと、ECS Taskで作成したバッチ2つを毎朝5:00に実行し、それら3つのバッチが終了した後に、CodeBuildで作成した別のバッチ1つを実行する必要があった。

この一連の処理を適切に制御するために、AWS Step Functionsを使用することにした。

実装概要

1. EventBridgeでStep Functionsを起動

  • EventBridgeのルールを設定し、ターゲットとしてStep Functionsを指定。
  • 毎朝5:00にStep Functionsが起動するように設定。

2. Step Functionsでの処理フロー

  1. CodeBuildバッチ1つとECS Taskバッチ2つを同時に実行。
  2. 各バッチの実行結果を監視し、エラーが発生した場合はキャッチする。
  3. 3つのバッチが全て終了した後、エラーの有無を確認。
    • エラーが発生している場合、処理を終了。
    • エラーが発生していない場合、CodeBuildのバッチを実行。

3. Terraformによる構築

EventBridgeのルール作成

resource "aws_cloudwatch_event_rule" "step_function_trigger" {
  name                = "step-function-trigger"
  schedule_expression = "cron(0 5 * * ? *)"
}

resource "aws_cloudwatch_event_target" "step_function" {
  rule      = aws_cloudwatch_event_rule.step_function_trigger.name
  arn       = aws_sfn_state_machine.batch_workflow.arn
  role_arn  = aws_iam_role.eventbridge_role.arn
}

Step Functionsの定義

resource "aws_sfn_state_machine" "batch_workflow" {
  name     = "batch-workflow"
  role_arn = aws_iam_role.step_function_role.arn
  definition = jsonencode({
    "Comment": "Batch processing workflow",
    "StartAt": "StartBatchJobs",
    "States": {
      "StartBatchJobs": {
        "Type": "Parallel",
        "Branches": [
          {
            "StartAt": "CodeBuildJob1",
            "States": {
              "CodeBuildJob1": {
                "Type": "Task",
                "Resource": "arn:aws:states:::codebuild:startBuild.sync",
                "Parameters": {
                  "ProjectName": "batch-job"
                },
                "Catch": [{
                  "ErrorEquals": ["States.ALL"],
                  "Next": "FailState"
                }],
                "End": true
              }
            }
          },
          {
            "StartAt": "ECSTask1",
            "States": {
              "ECSTask1": {
                "Type": "Task",
                "Resource": "arn:aws:states:::ecs:runTask.sync",
                "Parameters": {
                  "Cluster": "my-ecs-cluster",
                  "TaskDefinition": "ecs-task-1"
                },
                "Catch": [{
                  "ErrorEquals": ["States.ALL"],
                  "Next": "FailState"
                }],
                "End": true
              }
            }
          },
          {
            "StartAt": "ECSTask2",
            "States": {
              "ECSTask2": {
                "Type": "Task",
                "Resource": "arn:aws:states:::ecs:runTask.sync",
                "Parameters": {
                  "Cluster": "my-ecs-cluster",
                  "TaskDefinition": "ecs-task-2"
                },
                "Catch": [{
                  "ErrorEquals": ["States.ALL"],
                  "Next": "FailState"
                }],
                "End": true
              }
            }
          }
        ],
        "Next": "CheckErrors"
      },
      "CheckErrors": {
        "Type": "Choice",
        "Choices": [
          { "Variable": "$.errors", "BooleanEquals": true, "Next": "FailState" }
        ],
        "Default": "RunFinalCodeBuild"
      },
      "RunFinalCodeBuild": {
        "Type": "Task",
        "Resource": "arn:aws:states:::codebuild:startBuild.sync",
        "Parameters": {
          "ProjectName": "final-batch-job"
        },
        "End": true
      },
      "FailState": {
        "Type": "Fail"
      }
    }
  })
}

ECSの定義

resource "aws_ecs_task_definition" "ecs_task_1" {
  family                   = "ecs-task-1"
  requires_compatibilities = ["FARGATE"]
  network_mode             = "awsvpc"
  cpu                      = "512"
  memory                   = "1024"
  execution_role_arn       = aws_iam_role.ecs_execution_role.arn
  task_role_arn            = aws_iam_role.ecs_task_role.arn

  container_definitions = jsonencode([
    {
      "name": "ecs-task-1",
      "image": "my-container-image",
      "memory": 1024,
      "cpu": 512,
      "essential": true
    }
  ])
}

ハマったポイント

IAM PassRole の設定ミス

  • 初回の実行時にStep FunctionsからECS Taskの実行が失敗。
  • 調査の結果、Step FunctionsがECSを実行するためには iam:PassRole の権限が必要であることが判明。
  • 特にECSの実行には iam:PassRole の設定が必須。
  • 必要なIAMロールに iam:PassRole を付与することで解決。

まとめ

AWS Step Functionsを使用することで、複数のバッチ処理を制御し、エラーハンドリングを含めたワークフローを構築することができた。

Terraformを活用して構築したため、再現性が高く、管理も容易になった。

IAMの PassRole 権限は忘れがちだが、ECSの実行権限には必須であるため、今後のAWS開発でも注意していきたい。

タイトルとURLをコピーしました