はじめに
「複数のLambda関数を順番に呼び出したい」「エラーが起きたとき自動でリトライして、それでも失敗したら別の処理に切り替えたい」という要件を、AWS Step Functions は視覚的なフロー定義で実現します。
この記事では、AWSコンソールのみを使って、受注処理ワークフロー(注文検証 → 在庫確認・支払い並列処理 → 注文確定)をゼロから構築するハンズオンを紹介します。
入力: 注文データ(order_id / item_id / quantity)
↓
[ValidateOrder] 注文検証 ... Task + Retry + Catch
↓ 成功
[ProcessInParallel] 並列処理 ... Parallel + Catch
├─ [CheckInventory] 在庫確認
└─ [ProcessPayment] 支払い処理
↓ 成功
[ConfirmOrder] 注文確定
↓
終了(成功)
[HandleError] エラー処理(Catch 先)
↓
終了(エラー通知済み)このハンズオンで体験できること:
- Step Functions の Task / Parallel / Retry / Catch という基本パターン
- 並列ブランチの結果をリストとして次のステートに渡す仕組み
- Workflow Studio(新UI) の操作方法 — ビジュアルエディタと ASL コードエディタの関係
ResultPath: "$.error"でエラー情報を元の入力にマージして後続ステートに渡すテクニック
この記事は SAM版ハンズオン の比較記事です。
コンソール操作でStep Functionsの概念を視覚的に学び、SAMと何が違うのかを比較したい方向けです。
Step Functions 新UIで戸惑いやすいポイント(先読み)
操作を始める前に、2026年時点の新UIと旧UIの違いを把握しておきましょう。
| 変更点 | 旧UI | 新UI(現在) |
|---|---|---|
| 作成モーダル | 「空白のステートマシン」テンプレートを選択 | 3択モーダル が表示される |
| 作成選択肢 | テンプレートギャラリーのみ | 「自分で作成する」「Hello World を実行」「テンプレートを選択」の3択 |
| ASL入力の場所 | 作成フォームに「コード」タブ | Workflow Studio 内の「{ } コード」タブ |
| ロール設定タイミング | ASL入力と同じ画面 | 「設定」タブで別途確認 |
最大のハマりポイント:
「テンプレートを選択」を押してしまうと36個のテンプレートギャラリーが開きます。今回の目的には 「自分で作成する」 を選ぶ必要があります。これを知らずに迷う人が多いポイントです。
キーワード解説
| 用語 | 意味 |
|---|---|
| ステートマシン | ワークフローの全体定義。状態(State)の集合と遷移ルールをもつ |
| Task ステート | Lambda などの外部リソースを呼び出す状態 |
| Parallel ステート | 複数のブランチを同時に実行する状態。両ブランチの結果がリストで次のステートに渡る |
| Retry | エラー発生時に同じステートを自動で再実行するルール |
| Catch | リトライ後もエラーが続く場合に別のステートへ遷移するルール |
| ResultPath | Catch 時にエラー情報をどのフィールドに格納するかの指定("$.error" → 元の入力の error キーにマージ) |
| ASL | Amazon States Language。ステートマシン定義の JSON 形式 |
| Workflow Studio | Step Functions のビジュアルエディタ。フロー図と ASL コードを双方向に編集できる |
前提条件
| ツール | 確認コマンド | 備考 |
|---|---|---|
| AWSアカウント | — | IAMユーザーまたはルートユーザー |
| AWS CLI v2(任意) | aws --version | テスト実行を CLI で行う場合のみ必要 |
今回はほぼコンソール操作のみで完結します。
使用するAWSサービス
| サービス | 役割 | 料金 |
|---|---|---|
| Step Functions | ワークフロー(ステートマシン)の管理・実行 | 月4,000回の状態遷移まで無料(標準タイプ) |
| Lambda | 各ステートで実行されるビジネスロジック | 月100万リクエスト・400,000 GB-秒まで無料 |
| IAM | Lambda・Step Functionsの実行権限管理 | 無料 |
| CloudWatch Logs | Lambdaの実行ログ | 月5GBまで無料 |
全体の作業順序
① Lambda 関数を5つ作成する
↓(各関数の ARN が必要)
② Step Functions ステートマシンを作成する(新UI対応)
↓
③ 動作テスト(正常処理 / エラー処理)
↓
④ リソースの削除① Lambda 関数を5つ作成する
共通手順
AWSコンソール → Lambda → 「関数の作成」
| 設定項目 | 値 |
|---|---|
| 作成方法 | 一から作成 |
| ランタイム | Python 3.12 |
| アーキテクチャ | x86_64 |
| 実行ロール | 「基本的な Lambda アクセス権限で新しいロールを作成」(デフォルトのまま) |
各関数でコードを貼り付けたあと、必ず 「Deploy」 ボタンを押してコードを保存します。
1-1. ValidateFunction(注文検証)
関数名: ValidateFunction
コードエディタで lambda_function.py を開き、既存の内容を全て置き換えて以下を貼り付ける。
import json
def lambda_handler(event, context):
order_id = event.get("order_id")
item_id = event.get("item_id")
quantity = event.get("quantity", 0)
if not order_id:
raise ValueError("order_id が指定されていません")
if not item_id:
raise ValueError("item_id が指定されていません")
if not isinstance(quantity, int) or quantity <= 0:
raise ValueError(f"quantity は正の整数である必要があります: {quantity}")
result = {
**event, # 元の入力フィールドをすべて引き継ぐ(テスト用フラグを後続ステートに渡すため)
"validated": True,
}
print(json.dumps({"step": "validate", **result}, ensure_ascii=False))
return resultARN を控えておく: 関数ページ右上の「関数の ARN」をコピー(例: arn:aws:lambda:ap-northeast-1:123456789012:function:ValidateFunction)
1-2. InventoryFunction(在庫確認)
関数名: InventoryFunction
import json
def lambda_handler(event, context):
order_id = event.get("order_id")
item_id = event.get("item_id")
quantity = event.get("quantity", 1)
if item_id == "item-999":
raise ValueError(f"在庫不足: item_id={item_id}")
result = {
"order_id": order_id,
"item_id": item_id,
"quantity": quantity,
"stock_available": True,
}
print(json.dumps({"step": "inventory", **result}, ensure_ascii=False))
return resultARN を控えておく
1-3. PaymentFunction(支払い処理)
関数名: PaymentFunction
import json
def lambda_handler(event, context):
order_id = event.get("order_id")
quantity = event.get("quantity", 1)
# エラーテスト用: fail_payment=True の場合は例外発生
if event.get("fail_payment"):
raise RuntimeError(f"支払い処理に失敗: order_id={order_id}")
amount = quantity * 1000 # 1個 1,000円
result = {
"order_id": order_id,
"amount": amount,
"payment_status": "completed",
}
print(json.dumps({"step": "payment", **result}, ensure_ascii=False))
return resultARN を控えておく
1-4. ConfirmFunction(注文確定)
関数名: ConfirmFunction
import json
import datetime
def lambda_handler(event, context):
# Parallel ステートの後に呼ばれるため、event はリスト形式
# event[0]: CheckInventory(在庫確認)の結果
# event[1]: ProcessPayment(支払い処理)の結果
inventory_result = event[0]
payment_result = event[1]
order_id = inventory_result.get("order_id")
now = datetime.datetime.now(datetime.timezone.utc)
result = {
"order_id": order_id,
"item_id": inventory_result.get("item_id"),
"quantity": inventory_result.get("quantity"),
"amount": payment_result.get("amount"),
"confirmed_at": now.isoformat(),
"status": "confirmed",
}
print(json.dumps({"step": "confirm", **result}, ensure_ascii=False))
return resultARN を控えておく
Parallel ステート後の
eventがリストになる理由:ProcessInParallelの各ブランチの出力が配列でまとめられて次のステートに渡されます。event[0]が在庫確認の結果、event[1]が支払い処理の結果です。この仕様を知らないとlist indices must be integersエラーで詰まります。
1-5. ErrorHandlerFunction(エラー処理)
関数名: ErrorHandlerFunction
import json
def lambda_handler(event, context):
# ResultPath: "$.error" により、エラー情報が元の入力に付加されて渡される
error_info = event.get("error", {})
original_input = {k: v for k, v in event.items() if k != "error"}
result = {
"status": "error",
"error_type": error_info.get("Error", "Unknown"),
"error_cause": error_info.get("Cause", ""),
"original_input": original_input,
}
print(json.dumps({"step": "error_handler", **result}, ensure_ascii=False))
return resultARN を控えておく
② Step Functions ステートマシンを作成する
AWSコンソール → Step Functions → 「ステートマシンを作成」
2-1. 作成方法の選択(新UI:3択モーダル)
「ステートマシンを作成」ボタンを押すと 3択のモーダル が表示されます。

| 選択肢 | 説明 |
|---|---|
| Hello World を実行 | ガイド付きチュートリアル(今回は使わない) |
| テンプレートを選択 | 36個のテンプレートギャラリーが開く(今回は使わない) |
| 自分で作成する | ゼロからワークフローを作成する ← これを選ぶ |
「自分で作成する」 をクリックします。
「テンプレートを選択」を押してしまった場合:
テンプレートギャラリーが開きます。左上の「✕」で閉じて、改めてモーダルから「自分で作成する」を選んでください。
2-2. 名前とタイプの設定(モーダル)
「自分で作成する」をクリックすると Workflow Studio が開き、同時に設定モーダルが表示されます。
| 設定項目 | 値 |
|---|---|
| ステートマシン名 | OrderWorkflow |
| ステートマシンのタイプ | 標準 |
「続行」をクリックするとモーダルが閉じ、Workflow Studio の編集画面に切り替わります。
標準(Standard)と Express の違い:
標準タイプは「正確に1回実行」「最大1年の実行時間」「実行履歴をコンソールで確認可能」が特徴です。受注処理のような確実な実行が必要なユースケースに適しています。
2-3. ASL の入力(「{ } コード」タブ)
Workflow Studio の画面上部にある 「{ } コード」 タブをクリックしてコードエディタを表示します。
既存の内容を全て削除し、以下の JSON を貼り付けます。
【重要】
REPLACE_WITH_ARN_ValidateFunctionなどのプレースホルダーを、① で控えた実際の Lambda ARN に置き換えること。
{
"Comment": "受注処理ワークフロー(検証 → 並列処理 → 確定)",
"StartAt": "ValidateOrder",
"States": {
"ValidateOrder": {
"Type": "Task",
"Resource": "REPLACE_WITH_ARN_ValidateFunction",
"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": "REPLACE_WITH_ARN_InventoryFunction",
"End": true
}
}
},
{
"StartAt": "ProcessPayment",
"States": {
"ProcessPayment": {
"Type": "Task",
"Resource": "REPLACE_WITH_ARN_PaymentFunction",
"End": true
}
}
}
],
"Next": "ConfirmOrder",
"Catch": [
{
"ErrorEquals": ["States.ALL"],
"Next": "HandleError",
"ResultPath": "$.error"
}
]
},
"ConfirmOrder": {
"Type": "Task",
"Resource": "REPLACE_WITH_ARN_ConfirmFunction",
"End": true
},
"HandleError": {
"Type": "Task",
"Resource": "REPLACE_WITH_ARN_ErrorHandlerFunction",
"End": true
}
}
}貼り付けると 「フロー」タブ に切り替えると、フロー図が自動生成されます。ASL を正しく記述できているかを視覚的に確認できます。
2-4. 実行ロールの確認と作成(「設定」タブ)
画面上部の 「設定」 タブをクリックして実行ロールを確認します。
| 設定項目 | 値 |
|---|---|
| 実行ロール | 「新しいロールを作成」(デフォルトのまま) |
| ログ記録 | OFF(デフォルトのまま) |
「新しいロールを作成」を選ぶと、以下のような青いボックスが表示されます。
実行ロールは、完全な許可で作成されます。
StepFunctions-OrderWorkflow-role-XXXXという名前の新しい実行ロールが作成されます。ステートマシンで指定されたアクションに必要なすべての許可が自動生成されます。
「自動生成された許可を確認」を展開すると lambda:Invoke が含まれていることを確認できます。
右上の 「作成」 ボタンをクリックします。
IAMロールの自動作成について:
ASL 定義に記述した Lambda ARN に対してlambda:Invoke権限を持つロールが自動的に作成されます。SAM版ではLambdaInvokePolicyポリシーでこれを明示的に定義しています。
③ 動作テスト
Step Functions → OrderWorkflow → 「実行を開始」
テスト1: 正常処理
入力データ:
{
"order_id": "ORD-001",
"item_id": "item-001",
"quantity": 2
}「実行を開始」をクリックします。
実行グラフで確認:
- 全ステートが緑色になることを確認する
ProcessInParallelの2つのブランチが同時に緑になることを確認する(並列処理の視覚化)
出力を確認:
実行完了後、「出力」タブで以下のような JSON が表示されます。
{
"order_id": "ORD-001",
"item_id": "item-001",
"quantity": 2,
"amount": 2000,
"confirmed_at": "2026-03-01T10:00:00.000000+00:00",
"status": "confirmed"
}テスト2: 在庫切れエラー(Parallel Catch の確認)
入力データ:
{
"order_id": "ORD-002",
"item_id": "item-999",
"quantity": 1
}期待する動作:
ValidateOrder→ 成功ProcessInParallel→CheckInventoryがValueErrorを発生させるProcessInParallelの Catch が動作 →HandleErrorへ遷移HandleError→ 成功(エラー情報をログに記録して終了)
実行グラフで確認:
CheckInventoryが赤くなるProcessInParallelから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
}
}テスト3: 支払い失敗エラー(Parallel Catch の確認)
入力データ:
{
"order_id": "ORD-003",
"item_id": "item-001",
"quantity": 2,
"fail_payment": true
}期待する動作:
ValidateOrder→ 成功ProcessInParallel→ProcessPaymentがRuntimeErrorを発生させるProcessInParallelの Catch が動作 →HandleErrorへ遷移
テスト4: 検証エラー(ValidateOrder Retry + Catch の確認)
入力データ(order_id を省略):
{
"item_id": "item-001",
"quantity": 2
}期待する動作:
ValidateOrder→ValueError発生- Retry:
IntervalSeconds: 2で2秒後に自動リトライ(合計2回試行) - 2回とも失敗 → Catch が動作 →
HandleErrorへ遷移
Retry の確認方法:
実行グラフで ValidateOrder を選択 → 「イベント」タブ で以下の順序を確認します:
TaskStateEntered → TaskScheduled → TaskStarted → TaskFailed
→ TaskScheduled(リトライ1回目)→ TaskStarted → TaskFailed
→ TaskStateExited(Catch 発動)→ HandleError へValidateFunction が合計2回呼ばれていることが分かります。
④ リソースの削除
課金を止めるために、ハンズオン完了後は必ずリソースを削除してください。
1. ステートマシンを削除する
Step Functions → OrderWorkflow → 「削除」→ 確認テキストを入力 → 「削除」
削除後、ステータスが「削除中」に変わります。以下のようなメッセージが表示されます:
ステートマシンに削除のマークが付けられました。すべての実行が停止されると削除されます。
これは正常な動作です。実行中のワークフローがすべて終了するまで完全削除を待つ仕様のため、実行中のものがなければ数秒〜数十秒でリストから消えます。ページをリロードして確認します。
2. Lambda 関数を5つ削除する
Lambda → 関数一覧 → 各関数を選択 → 「アクション」→「削除」
削除対象:
ValidateFunctionInventoryFunctionPaymentFunctionConfirmFunctionErrorHandlerFunction
3. IAM ロールを削除する(任意)
Step Functions の実行ロール(StepFunctions-OrderWorkflow-role-XXXX)と、Lambda 関数のロール(ValidateFunction-role-XXXX など5つ)を削除します。
IAM → ロール → 各ロールを検索して削除
4. CloudWatch Logs のロググループを削除する(任意)
CloudWatch → ロググループ → 各 Lambda の /aws/lambda/関数名 を削除
SAMとの対比
| SAMの記述 | コンソールでやること |
|---|---|
AWS::Serverless::StateMachine | Step Functions → ステートマシンを作成 |
Type: STANDARD | タイプ = 「標準」 |
Definition: {...} | 「{ } コード」タブに ASL JSON を貼り付け |
DefinitionSubstitutions | JSON 内の ARN プレースホルダーを手動で置換 |
LambdaInvokePolicy × 5 | 「設定」タブ → 「新しいロールを作成」で自動生成 |
sam delete | Lambda × 5 / ステートマシン / IAM ロール / ロググループを個別に削除 |
トラブルシューティング
| 症状 | 原因 | 対処 |
|---|---|---|
実行が即座に ExecutionFailed になる | ASL 内の Lambda ARN が間違っている | ① で控えた ARN と再照合する |
| 「テンプレートを選択」を押してギャラリーが開いた | 新UI操作ミス | ✕で閉じ、モーダルから「自分で作成する」を選ぶ |
| 「{ } コード」タブが見つからない | モーダルが前面に出ている | 「続行」でモーダルを閉じてから Workflow Studio を操作する |
HandleError に渡る error_cause が空 | Python 例外が Lambda レベルでハンドルされている | コードの raise が正しく記述されているか確認 |
ProcessInParallel が一方しか実行されない | Parallel ブランチの定義ミス | ASL JSON の Branches 配列に2つの要素があるか確認 |
ConfirmFunction でエラー: list indices must be integers | event[0] / event[1] で取り出しているが、入力が配列でない | ProcessInParallel の直後にのみ呼ばれる関数かを確認する |
| ステートマシン削除後「削除中」のまま消えない | 実行中のワークフローが残っている | 実行一覧から実行中のものを停止してから再確認 |
まとめ
今回のハンズオンで体験できたこと:
| 確認項目 | 内容 |
|---|---|
| Task + Retry + Catch | ValidateOrder で注文検証 → リトライ → それでも失敗したらエラーハンドラへ |
| Parallel ステート | 在庫確認と支払い処理を同時実行し、両結果をリストで次へ渡す |
| ResultPath | "$.error" でエラー情報を元の入力にマージ → エラーハンドラで参照 |
| Workflow Studio | ASL コードと視覚フロー図を双方向で確認できる新UI |
| 新UI操作 | 3択モーダル → 「自分で作成する」→「{ } コード」タブ → 「設定」タブ の流れ |
コンソール版とSAM版を比較してみる
コンソールでStep Functionsの概念を理解したら、SAMで同じ構成をコードで定義することで「SAMが何を自動化しているか」が明確になります。DefinitionSubstitutions による ARN の自動差し込みや、LambdaInvokePolicy によるワンライン権限付与など、コンソールでの手動操作がコードに対応しています。
コメント