SJ blog
backend
A

信頼度ランク

S 公式ソース確認済み
A 成功実績多数・失敗例少数
B 賛否両論
C 動作未確認・セキュリティリスク高
Z 個人所感

AWS Step Functions — サーバーレスワークフローの設計パターン

AWS Step FunctionsのStandard vs Expressワークフロー、状態タイプ(Task/Choice/Parallel/Wait/Map)、エラーハンドリングとリトライ、Lambda/ECS/SQS統合パターン、SAGAパターン実装を解説。

一言結論

Step Functionsはエラーハンドリング・リトライ・分岐ロジックをコードではなくASL定義として外部化できるため複雑な分散処理のオーケストレーションに適しており、SDK統合でLambdaを介さずDynamoDB等に直接アクセスできる点が疎結合アーキテクチャの鍵だ。

Step Functions の概要

Step Functionsはサーバーレスのビジュアルワークフローサービスで、複数のAWSサービスをオーケストレーションする。複雑な分散処理フローをJSONで定義して管理できる。

Step Functions のユースケース:
  → 複数のLambda関数を順次/並列に実行
  → エラーハンドリングとリトライロジックの一元管理
  → 長時間実行ワークフロー(人間の承認待ち等)
  → マイクロサービスのオーケストレーション
  → バッチ処理のコーディネーション

Standard vs Express ワークフロー

特徴StandardExpress
最大実行時間1年5分
実行開始レート2,000/秒100,000/秒
実行履歴保存90日CloudWatch Logsのみ
実行保証Exactly-onceAt-least-once
料金状態遷移ごと期間 + リクエスト数
ユースケース長時間処理、重複不可高頻度・短時間、IoT、ストリーミング

Amazon States Language(ASL)の基本

{
  "Comment": "注文処理ワークフロー",
  "StartAt": "ValidateOrder",
  "States": {
    "ValidateOrder": {
      "Type": "Task",
      "Resource": "arn:aws:lambda:ap-northeast-1:123456789012:function:validate-order",
      "Next": "CheckInventory",
      "Retry": [{
        "ErrorEquals": ["Lambda.ServiceException", "Lambda.AWSLambdaException"],
        "IntervalSeconds": 2,
        "MaxAttempts": 3,
        "BackoffRate": 2
      }],
      "Catch": [{
        "ErrorEquals": ["ValidationError"],
        "Next": "ValidationFailed"
      }]
    },
    "CheckInventory": {
      "Type": "Choice",
      "Choices": [{
        "Variable": "$.inventory",
        "NumericGreaterThan": 0,
        "Next": "ProcessPayment"
      }],
      "Default": "OutOfStock"
    },
    "ProcessPayment": {
      "Type": "Parallel",
      "Branches": [
        {
          "StartAt": "ChargeCreditCard",
          "States": {
            "ChargeCreditCard": {
              "Type": "Task",
              "Resource": "arn:aws:lambda:...:function:charge-card",
              "End": true
            }
          }
        },
        {
          "StartAt": "SendConfirmationEmail",
          "States": {
            "SendConfirmationEmail": {
              "Type": "Task",
              "Resource": "arn:aws:lambda:...:function:send-email",
              "End": true
            }
          }
        }
      ],
      "Next": "OrderComplete"
    },
    "OrderComplete": {
      "Type": "Succeed"
    },
    "ValidationFailed": {
      "Type": "Fail",
      "Error": "ValidationError",
      "Cause": "Order validation failed"
    },
    "OutOfStock": {
      "Type": "Fail",
      "Error": "OutOfStock",
      "Cause": "Item is out of stock"
    }
  }
}

状態タイプの一覧

Task: AWSサービスを呼び出す
  Resource: Lambda, ECS, SQS, SNS, DynamoDB, SageMaker等

Choice: 条件分岐(if/else)
  Choices: 条件と遷移先のリスト
  Default: デフォルト遷移先

Parallel: 並列実行(全ブランチが完了するまで待つ)
  Branches: 並列実行するサブワークフローのリスト

Map: 配列の各要素に対して並列実行
  MaxConcurrency: 最大同時実行数(0で無制限)

Wait: 指定時間待機またはタイムスタンプまで待機
  Seconds: 待機秒数
  Timestamp: 特定の日時まで待機

Pass: 変換のみ(Lambdaを呼ばずデータを加工)

Succeed: ワークフロー成功終了

Fail: ワークフロー失敗終了

SDK統合(オプティミズドインテグレーション)

// DynamoDBへの直接アクセス(Lambda不要)
{
  "SaveOrder": {
    "Type": "Task",
    "Resource": "arn:aws:states:::dynamodb:putItem",
    "Parameters": {
      "TableName": "Orders",
      "Item": {
        "orderId": {"S.$": "$.orderId"},
        "status": {"S": "PROCESSING"},
        "amount": {"N.$": "States.Format('{}', $.amount)"}
      }
    },
    "Next": "NextState"
  }
}

Wait for Callback パターン(人間の承認)

{
  "WaitForApproval": {
    "Type": "Task",
    "Resource": "arn:aws:states:::sqs:sendMessage.waitForTaskToken",
    "Parameters": {
      "QueueUrl": "https://sqs.ap-northeast-1.amazonaws.com/123456789012/approval-queue",
      "MessageBody": {
        "TaskToken.$": "$$.Task.Token",
        "OrderId.$": "$.orderId",
        "Amount.$": "$.amount"
      }
    },
    "HeartbeatSeconds": 86400,
    "Next": "ApprovalReceived"
  }
}
# 承認完了後にStep Functionsに通知
import boto3

sfn = boto3.client('stepfunctions')

def approve_order(task_token: str):
    """承認ボタンクリック時の処理"""
    sfn.send_task_success(
        taskToken=task_token,
        output='{"approved": true, "approver": "manager@example.com"}'
    )

def reject_order(task_token: str, reason: str):
    """拒否ボタンクリック時の処理"""
    sfn.send_task_failure(
        taskToken=task_token,
        error='OrderRejected',
        cause=reason
    )

SAGA パターン(分散トランザクション)

SAGAパターン: マイクロサービスにまたがるトランザクションを
              補償トランザクションで管理

フロー:
  1. 在庫を予約
  2. 支払いを処理
  3. 配送を手配
  
いずれかで失敗した場合:
  3失敗 → 2を補償(払い戻し)→ 1を補償(在庫戻し)
  
Step Functionsのエラーハンドリングで実装:
  → Catch でエラーを捕捉
  → 補償処理のLambdaを呼び出す

試験頻出ポイント

シナリオ回答
複数Lambdaを順序制御して実行Step Functions
人間の承認を待つワークフローWait for Callback パターン
配列の全要素を並列処理Map 状態
最大1年の長時間ワークフローStandard ワークフロー
高頻度(100,000/秒)の短時間処理Express ワークフロー

まとめ

Step Functionsはサーバーレスのワークフローオーケストレーションサービスで、複数のAWSサービスを視覚的に連携させる。StandardとExpressの使い分け、豊富な状態タイプ、SDK統合によるLambda不要の直接サービス呼び出しがポイントだ。