AWSハンズオン - Step Functions + Lambda で受注処理ワークフローをSAMで構築しよう【コンソール版との比較付き】

AWS Basic
スポンサーリンク
スポンサーリンク

はじめに

「複数のLambda関数をオーケストレーションするワークフローを、コードで管理したい」という要件に、AWS SAM(Serverless Application Model) は最適な選択肢のひとつです。

この記事では、AWS SAM を使って、受注処理ワークフロー(注文検証 → 在庫確認・支払い並列処理 → 注文確定)をゼロから構築するハンズオンを紹介します。

入力: {"order_id": "ORD-001", "item_id": "item-001", "quantity": 2}
  ↓
[ValidateOrder] 注文検証(Retry + Catch)
  ↓ 成功
[ProcessInParallel] 並列処理(Catch)
  ├─ [CheckInventory] 在庫確認
  └─ [ProcessPayment] 支払い処理
  ↓ 成功(結果リスト: [inventory_result, payment_result])
[ConfirmOrder] 注文確定
  ↓
終了(成功)

[HandleError] エラー処理(Catch 先)
  ↓
終了(エラー通知済み)

このハンズオンで体験できること:

  • AWS::Serverless::StateMachine を使った Step Functions の SAM 定義
  • DefinitionSubstitutions で ASL 内の Lambda ARN を 自動差し込みする仕組み
  • LambdaInvokePolicy による1行での権限付与(コンソール版ではIAMロールを自動生成)
  • CLI でのテスト実行 + コンソールの実行グラフで視覚的に確認

このハンズオンの特徴:

  • sam build + sam deploy2コマンドで全リソースをデプロイ
  • Step Functions(ステートマシン)+ Lambda × 5 + IAM ロール × 6 を template.yaml 1ファイルで管理
  • sam delete全リソースを一括削除(コンソール版では5つのLambda・ステートマシン・IAMロールを個別に削除)

Amazon検索[本 AWS 開発]

スポンサーリンク

SAM vs コンソール:どれだけ違うか

比較項目SAM(コード)コンソール(手動)
Lambda ARN の参照${ValidateFunctionArn} で自動差し込み5関数のARNを手動でコピー・貼り付け
IAM ロールLambdaInvokePolicy × 5 で自動生成「新しいロールを作成」で自動生成(1回限り)
ASL 定義の管理template.yaml で Git 管理コンソールのエディタのみ
削除sam delete 1コマンドLambda × 5 / ステートマシン / IAMロール / ロググループを個別に削除
再現性チームで同じ環境を即座に再現できる手順書が必要

スポンサーリンク

キーワード解説

用語意味
ステートマシンワークフローの全体定義。状態(State)の集合と遷移ルールをもつ
Task ステートLambda などの外部リソースを呼び出す状態
Parallel ステート複数のブランチを同時に実行する状態。両ブランチの結果がリストで次のステートに渡る
Retryエラー発生時に同じステートを自動で再実行するルール
Catchリトライ後もエラーが続く場合に別のステートへ遷移するルール
ResultPathCatch 時にエラー情報をどのフィールドに格納するかの指定("$.error" → 元の入力の error キーにマージ)
ASLAmazon States Language。ステートマシン定義の JSON 形式
DefinitionSubstitutionsASL 内の ${変数名} を実際の値(ARN など)に置換するSAMの仕組み

前提条件

ツール確認コマンド最低バージョン目安
AWS CLI v2aws --version2.x
AWS SAM CLIsam --version1.x
Python 3.12python --version3.12
Gitgit --version-
VSCode-最新版推奨
aws sts get-caller-identity

アカウントIDが表示されれば認証設定済みです。


使用するAWSサービス

サービス役割料金
Step Functionsワークフロー(ステートマシン)の管理・実行月4,000回の状態遷移まで無料(標準タイプ)
Lambda各ステートで実行されるビジネスロジック(5関数)月100万リクエスト・400,000 GB-秒まで無料
IAMLambda・Step Functionsの実行権限管理無料
S3SAM デプロイパッケージ置き場少量のため実質無料
CloudWatch LogsLambdaの実行ログ月5GBまで無料

Step 1: プロジェクトフォルダを開く

cd C:\my-aws\aws-learning-projects\step-functions-lambda

フォルダ構造

step-functions-lambda/
├── template.yaml           # SAMテンプレート(Step Functions + Lambda 定義)
├── samconfig.toml          # デプロイ設定(gitignore 対象・毎回手動作成が必要)
├── docs/
│   ├── 1_console.md        # AWSコンソール版手順
│   └── 2_sam.md            # SAM版手順
└── src/
    ├── validate.py         # 注文検証 Lambda
    ├── inventory.py        # 在庫確認 Lambda
    ├── payment.py          # 支払い処理 Lambda
    ├── confirm.py          # 注文確定 Lambda
    └── error_handler.py    # エラー処理 Lambda

Step 2: SAMテンプレートの確認(template.yaml)

template.yaml は全 AWSリソースの設計図です。ポイントを確認しておきます。

Lambda 関数の定義

Globals:
  Function:
    Runtime: python3.12
    Timeout: 10
    MemorySize: 128

Resources:
  ValidateFunction:
    Type: AWS::Serverless::Function
    Properties:
      CodeUri: src/           # src/ 配下の全 .py を1つのパッケージとしてデプロイ
      Handler: validate.lambda_handler

  InventoryFunction:          # 在庫確認(Parallel ブランチ 1)
  PaymentFunction:            # 支払い処理(Parallel ブランチ 2)
  ConfirmFunction:            # 注文確定
  ErrorHandlerFunction:       # エラー処理(Catch 先)

ポイント: 5つの Lambda 関数が全て CodeUri: src/ を共有しています。SAM は src/ フォルダを1つの ZIP パッケージとして S3 にアップロードし、各関数は Handler でどのファイル・関数を使うかを指定します。

ステートマシンの定義

  OrderWorkflow:
    Type: AWS::Serverless::StateMachine
    Properties:
      Type: STANDARD
      Definition:
        StartAt: ValidateOrder
        States:
          ValidateOrder:
            Type: Task
            Resource: "${ValidateFunctionArn}"   # DefinitionSubstitutions で実際の ARN に置換
            Next: ProcessInParallel
            Retry:
              - ErrorEquals: [States.ALL]
                IntervalSeconds: 2
                MaxAttempts: 1
                BackoffRate: 2.0
            Catch:
              - ErrorEquals: [States.ALL]
                Next: HandleError
                ResultPath: "$.error"

          ProcessInParallel:
            Type: Parallel
            Branches:
              - StartAt: CheckInventory
                States:
                  CheckInventory:
                    Type: Task
                    Resource: "${InventoryFunctionArn}"
                    End: true
              - StartAt: ProcessPayment
                States:
                  ProcessPayment:
                    Type: Task
                    Resource: "${PaymentFunctionArn}"
                    End: true
            Next: ConfirmOrder
            Catch:
              - ErrorEquals: [States.ALL]
                Next: HandleError
                ResultPath: "$.error"

          ConfirmOrder:
            Type: Task
            Resource: "${ConfirmFunctionArn}"
            End: true

          HandleError:
            Type: Task
            Resource: "${ErrorHandlerFunctionArn}"
            End: true

      DefinitionSubstitutions:           # ${変数名} を実際の ARN に自動置換
        ValidateFunctionArn: !GetAtt ValidateFunction.Arn
        InventoryFunctionArn: !GetAtt InventoryFunction.Arn
        PaymentFunctionArn: !GetAtt PaymentFunction.Arn
        ConfirmFunctionArn: !GetAtt ConfirmFunction.Arn
        ErrorHandlerFunctionArn: !GetAtt ErrorHandlerFunction.Arn

      Policies:                          # ステートマシンが Lambda を呼び出す IAM 権限
        - LambdaInvokePolicy:
            FunctionName: !Ref ValidateFunction
        - LambdaInvokePolicy:
            FunctionName: !Ref InventoryFunction
        - LambdaInvokePolicy:
            FunctionName: !Ref PaymentFunction
        - LambdaInvokePolicy:
            FunctionName: !Ref ConfirmFunction
        - LambdaInvokePolicy:
            FunctionName: !Ref ErrorHandlerFunction

template.yaml のポイント解説

ポイント説明
DefinitionSubstitutionsASL 内の ${ValidateFunctionArn} などを !GetAtt ValidateFunction.Arn で取得した実際の ARN に置換する。コンソール版で5回ARNをコピーする手間がなくなる
LambdaInvokePolicy × 5SAM 組み込みポリシー。lambda:InvokeFunction 権限を1行で付与。コンソール版ではIAMロールの自動生成で対応
Type: STANDARD監査ログ・正確に1回実行・長時間実行対応。コンソール版では「標準」を選択する部分に対応
ResultPath: "$.error"エラー情報を元の入力の $.error フィールドにマージして HandleError へ渡す
CodeUri: src/(共有)5関数で1つの src/ パッケージを共有。コードを変更すると全関数に反映される

Step 3: Lambda コードの確認(src/)

各ファイルの役割を確認しておきます。

ファイルステート特記事項
validate.pyValidateOrderorder_id / item_id / quantity を検証。欠けていると ValueError
inventory.pyCheckInventoryitem-999ValueError(在庫切れテスト用)
payment.pyProcessPaymentfail_payment=TrueRuntimeError(支払い失敗テスト用)
confirm.pyConfirmOrderevent[0](在庫確認結果)と event[1](支払い結果)を受け取る。Parallel 後はリスト形式になる
error_handler.pyHandleErrorevent["error"] にエラー情報、それ以外に元の入力が格納されている

各 Python コードの全文はコンソール版記事を参照してください。
SAM版・コンソール版で使用する Lambda コードは共通です。コンソール版では各関数ごとにコードを貼り付ける手順とあわせて全文を掲載しています。

AWSコンソールだけでStep Functions + Lambdaワークフローを構築する手順【SAM版との比較付き / 新UI対応】

confirm.pyevent[0] / event[1] について:
Parallel ステートが成功すると、各ブランチの出力が**配列(リスト)**にまとめられて次のステートに渡されます。このため ConfirmFunction は event[0] で在庫確認結果、event[1] で支払い結果にアクセスしています。この仕様を知らないと list indices must be integers エラーで詰まります。


Step 4: samconfig.toml を作成する

samconfig.toml.gitignore で管理外のため、毎回手動で作成する必要があります。

step-functions-lambda/samconfig.toml を新規作成して以下を貼り付けます。

version = 0.1

[default.deploy.parameters]
stack_name = "step-functions-lambda-stack"
resolve_s3 = true
s3_prefix = "step-functions-lambda-stack"
region = "ap-northeast-1"
confirm_changeset = true
capabilities = "CAPABILITY_IAM"
disable_rollback = true
image_repositories = []

[default.global.parameters]
region = "ap-northeast-1"

samconfig.toml の置き場所:
step-functions-lambda/ フォルダの直下に置く必要があります。


Step 5: sam build(ビルド)

cd C:\my-aws\aws-learning-projects\step-functions-lambda
sam build

成功すると以下のように表示されます。

Build Succeeded

Built Artifacts  : .aws-sam/build
Built Template   : .aws-sam/build/template.yaml

sam build が行っていること:

  • src/ フォルダを ZIP パッケージ化して .aws-sam/build/ に配置
  • template.yaml.aws-sam/build/template.yaml にコピー
  • Lambda デプロイの準備を整える

Step 6: sam deploy(デプロイ)

sam deploy

変更内容が表示されて確認を求められます。

Deploy this changeset? [y/N]: y

y を入力して進めます。数分でデプロイが完了します。

デプロイ完了の確認

ターミナルに Outputs が表示されます。

Outputs
----------------------------------------------------------------------
Key    OrderWorkflowArn
Value  arn:aws:states:ap-northeast-1:123456789012:stateMachine:step-functions-lambda-stack-order-workflow

Key    OrderWorkflowName
Value  step-functions-lambda-stack-order-workflow
----------------------------------------------------------------------

OrderWorkflowArn を控えておきます。(テスト実行コマンドで使用)

デプロイされるリソース一覧

Step Functions ステートマシン × 1  : step-functions-lambda-stack-order-workflow
Lambda 関数 × 5                    : step-functions-lambda-stack-ValidateFunction-XXXX 他
IAM ロール × 6                     : ステートマシン用 × 1 / Lambda 用 × 5
S3                                 : SAM デプロイパッケージ
CloudWatch Logs                    : Lambda 自動生成ログ × 5

Step 7: 動作テスト

事前準備: ARN を変数に設定する

set SM_ARN=arn:aws:states:ap-northeast-1:123456789012:stateMachine:step-functions-lambda-stack-order-workflow

123456789012 を自分のアカウントIDに置き換えてください(Outputs の値をそのままコピーすればよいです)。


テスト1: 正常処理

aws stepfunctions start-execution ^
  --state-machine-arn %SM_ARN% ^
  --name "test-normal-1" ^
  --input "{\"order_id\": \"ORD-001\", \"item_id\": \"item-001\", \"quantity\": 2}" ^
  --region ap-northeast-1

レスポンス例:

{
    "executionArn": "arn:aws:states:ap-northeast-1:123456789012:execution:...:test-normal-1",
    "startDate": "2026-03-01T10:00:00.000000+09:00"
}

実行結果を確認(数秒後):

aws stepfunctions describe-execution ^
  --execution-arn "上記の executionArn" ^
  --region ap-northeast-1

"status": "SUCCEEDED" と以下のような出力が表示されます。

{
  "order_id": "ORD-001",
  "item_id": "item-001",
  "quantity": 2,
  "amount": 2000,
  "confirmed_at": "2026-03-01T01:00:00.000000+00:00",
  "status": "confirmed"
}

AWSコンソールで実行グラフを確認(任意):

Step Functions → ステートマシン → step-functions-lambda-stack-order-workflow → 実行一覧 → test-normal-1 をクリックすると、全ステートが緑色になり ProcessInParallel の2ブランチが同時に実行されたことを視覚的に確認できます。


テスト2: 在庫切れエラー(ProcessInParallel Catch の確認)

aws stepfunctions start-execution ^
  --state-machine-arn %SM_ARN% ^
  --name "test-inventory-error" ^
  --input "{\"order_id\": \"ORD-002\", \"item_id\": \"item-999\", \"quantity\": 1}" ^
  --region ap-northeast-1

期待する動作:

  1. ValidateOrder → 成功
  2. ProcessInParallelCheckInventoryValueError(在庫切れ)を発生させる
  3. ProcessInParallel の Catch が動作 → HandleError へ遷移
  4. 実行ステータス: SUCCEEDED(HandleError が正常完了)

出力例:

{
  "status": "error",
  "error_type": "ValueError",
  "error_cause": "在庫不足: item_id=item-999",
  "original_input": {
    "order_id": "ORD-002",
    "item_id": "item-999",
    "quantity": 1,
    "validated": true
  }
}

実行ステータスが SUCCEEDED になる理由:
HandleError 関数が正常終了(return result)しているため、ステートマシン全体としては「成功」扱いになります。エラーが「処理されずに残った」場合は FAILED になります。


テスト3: 支払い失敗エラー(ProcessInParallel Catch の確認)

aws stepfunctions start-execution ^
  --state-machine-arn %SM_ARN% ^
  --name "test-payment-error" ^
  --input "{\"order_id\": \"ORD-003\", \"item_id\": \"item-001\", \"quantity\": 2, \"fail_payment\": true}" ^
  --region ap-northeast-1

ProcessPaymentRuntimeError を発生させ、同様に HandleError へ遷移します。


テスト4: 検証エラー(ValidateOrder Retry + Catch の確認)

aws stepfunctions start-execution ^
  --state-machine-arn %SM_ARN% ^
  --name "test-validate-error" ^
  --input "{\"item_id\": \"item-001\", \"quantity\": 2}" ^
  --region ap-northeast-1

order_id を省略しているため ValidateOrderValueError を発生させます。

Retry の確認(AWSコンソール):

Step Functions コンソールの実行グラフで ValidateOrder を選択 → 「イベント」タブ で以下の順序を確認します:

TaskStateEntered → TaskScheduled → TaskStarted → TaskFailed
  → TaskScheduled(リトライ1回目)→ TaskStarted → TaskFailed
  → TaskStateExited(Catch 発動)→ HandleError へ

ValidateFunction が合計2回呼ばれてから HandleError へ遷移することが分かります。


Step 8: AWSコンソールで確認(任意)

SAMでデプロイしたリソースはコンソールで確認できます。

  • Step Functions: ステートマシン一覧 → step-functions-lambda-stack-order-workflow → 各実行のグラフを確認
  • Lambda: Lambda → 関数 → step-functions-lambda-stack-ValidateFunction-XXXX → 「モニタリング」→ 呼び出し回数を確認
  • CloudWatch Logs: Lambda → 対象関数 → 「モニタリング」タブ → 「CloudWatch Logs を表示」

Step 9: リソースの削除

課金を止めるために、ハンズオン完了後は必ずリソースを削除してください。

sam delete --stack-name step-functions-lambda-stack --region ap-northeast-1

対話式で確認が入ります。両方 y で進めます。

Are you sure you want to delete the stack step-functions-lambda-stack? [y/N]: y
Are you sure you want to delete the folder step-functions-lambda-stack in S3? [y/N]: y

削除完了の確認

aws cloudformation describe-stacks --stack-name step-functions-lambda-stack --region ap-northeast-1
An error occurred (ValidationError): Stack with id step-functions-lambda-stack does not exist

このメッセージが表示されれば削除完了です。

sam delete で削除されるリソース一覧

リソース
Step Functions ステートマシン× 1
Lambda 関数× 5
IAM ロール(ステートマシン用・Lambda 用)× 6
Lambda デプロイパッケージ(S3)× 1
CloudWatch Logs ロググループ× 5

コンソール版との大きな違い(SAMのメリット):
コンソール版では Lambda × 5 / ステートマシン / IAM ロール × 6 / ロググループを個別に削除する必要があります。
SAMでは sam delete 1コマンドで全リソースを一括削除できます。


トラブルシューティング

症状原因対処
sam build が失敗するsrc/ フォルダ内のファイルが存在しないsrc/ 配下に5つの .py ファイルがあるか確認
sam deployMissing --stack-name エラーsamconfig.toml がない、または場所が違うstep-functions-lambda/ 直下に samconfig.toml を作成する
実行が即座に FAILED になるLambda ARN が間違っているsam deploy のエラーログを確認
テストで executionArn が同じ名前で失敗する--name が重複している--name のサフィックスを変えて再実行する(例: test-normal-2
describe-executionstatusRUNNING のままLambda がまだ実行中数秒〜数十秒待ってから再実行する
ConfirmFunction でエラー: list index out of rangeParallel ブランチが正常完了していないProcessInParallel の後にのみ呼ばれる関数かを確認する

まとめ

今回のハンズオンで実現したこと:

確認項目内容
SAM でのステートマシン定義AWS::Serverless::StateMachine + DefinitionSubstitutions で ARN を自動差し込み
Lambda × 5 の一括デプロイCodeUri: src/ 共有パッケージ + Handler で各関数を定義
Retry + CatchValidateOrder でリトライ → 失敗 → HandleError へ遷移
Parallel + Catch在庫確認と支払い処理を同時実行 → 一方が失敗したら HandleError へ
一括削除sam delete で全リソースをクリーンアップ

SAMのメリットを実感できたポイント

  • DefinitionSubstitutions により Lambda ARN のコピー貼り付けが不要
  • LambdaInvokePolicy × 5 で IAM 権限設定が1行ずつで完結
  • sam delete でステートマシン・Lambda 5つ・IAM ロール 6つを一括削除

コンソール版と比較してみる

SAMが裏で何をやっているか、同じ構成をAWSコンソールのみで構築する手順をまとめました。Workflow Studioの新UI(3択モーダル・「{ } コード」タブ)での操作方法や、コンソール版ならではのつまずきポイントを解説しています。


関連記事

Amazon検索[本 AWS 開発]

コメント