AWS Step Functionsって名前は聞いたことあるけど、実際どこで使うのかよくわからない——。オンプレミスでバッチ処理や複雑なワークフローを組んできたエンジニアほど、そう感じることが多いと思います。
オンプレでは、複数の処理をつなぐときにシェルスクリプトや自社製のジョブスケジューラーを駆使してきたはずです。クラウド移行後も「とりあえずLambdaを何本か書いて、SQSでつなげばいい」と考えがちですが、処理が複雑になるにつれて、エラーハンドリング・リトライ・状態管理が手に負えなくなってきます。
この記事では、AWS Step Functionsについて、オンプレ経験者にもわかりやすく解説します。ステートマシンの基本概念から、Lambda連携・エラーハンドリング・料金体系・Standard/Expressの使い分けまで、現場で即戦力になるレベルで掘り下げます。
なぜStep Functionsなのか? オンプレのジョブスケジューラーとの違い
オンプレ時代、複数のバッチ処理を連携させるときはどうしていましたか?
JP1やHinemos、あるいは独自シェルスクリプトのif地獄——。エラーが発生したとき、どのステップが失敗したのかログを追いかけ、手動でリトライして、ときには深夜に呼び出される。そういう経験をしてきた方は多いでしょう。
AWS Step Functionsが解決するのは、まさにその問題です。
Step Functionsとは何か
AWS Step Functionsは、ステートマシン(State Machine)という概念でワークフローを定義・実行するマネージドサービスです。各処理をJSON形式のAmazon States Language(ASL)で記述し、処理間の遷移・分岐・エラーハンドリング・タイムアウト・リトライをアプリコードではなく構成ファイルとして管理します。
オンプレのジョブスケジューラーとの最大の違いは以下の3点です。
・状態が可視化される: AWSコンソール上でフロー図として確認でき、どのステップが失敗したか一目でわかります
・サーバー管理不要: スケジューラー専用サーバーを保守する必要がなく、実行数に応じた従量課金になります
・エラーハンドリングが宣言的: 「このエラーコードが出たら3回リトライし、その後はこちらへ遷移」をJSONで記述できます
オンプレの「スクリプトを書き足してなんとか対処」から「設計図を見ながら管理できる」状態に変わる——それがStep Functionsの本質です。
基本概念:ステートマシンと8種類の状態
Step Functionsを理解するうえで、「ステートマシン」という概念を押さえておく必要があります。ステートマシンとは、「今どの状態にあるか(State)」と「どの条件でどの状態に遷移するか(Transition)」を定義した仕組みのことです。
1. 状態(State)の種類
Step Functionsで使える状態の種類は以下の8種類です。
| 状態タイプ | 役割 | 典型的な使いどころ |
|---|---|---|
| Task | Lambda・ECS・外部APIなどを呼び出す | 実際の処理のほぼすべて |
| Choice | 条件分岐(if / switch相当) | 処理結果によってフローを切り替える |
| Wait | 指定時間または特定日時まで待機 | 外部システムの処理完了待ち・定時実行調整 |
| Parallel | 複数ブランチを並列実行 | 互いに依存しない処理の同時実行 |
| Map | 配列の各要素に同じ処理を適用 | 複数ファイルの並列変換・一括メール送信 |
| Pass | 処理なしで次の状態へ(データ整形のみ) | テスト・デバッグ・固定値の注入 |
| Succeed | ワークフロー正常終了 | フローの出口 |
| Fail | ワークフロー異常終了 | リカバリー不能なエラー時の終端 |
2. Amazon States Language(ASL)の基本構造
ステートマシンはJSON形式のASLで記述します。シンプルな2ステートのフローを見てみましょう。
# シンプルな2ステートのワークフロー例(Amazon States Language) { "Comment": "注文処理ワークフロー", "StartAt": "ValidateOrder", "States": { "ValidateOrder": { "Type": "Task", "Resource": "arn:aws:lambda:ap-northeast-1:123456789012:function:validate-order", "Next": "ProcessPayment" }, "ProcessPayment": { "Type": "Task", "Resource": "arn:aws:lambda:ap-northeast-1:123456789012:function:process-payment", "End": true } } }
`StartAt` で最初の状態を指定し、各状態の `Next` で次の遷移先を指定します。最後の状態には `”End”: true` を付けます。ビジュアルエディタがリアルタイムでフロー図を表示するため、JSONを書きながら視覚的に確認できます。
3. StandardワークフローとExpressワークフローの違い
Step Functionsには2種類のワークフロータイプがあり、ユースケースに応じて選択します。
| 項目 | Standard(標準) | Express(高速) |
|---|---|---|
| 最大実行時間 | 1年 | 5分 |
| 実行保証 | Exactly-once(厳密に1回) | At-least-once(1回以上) |
| 料金体系 | 状態遷移数ごとの従量課金 | 実行時間+リクエスト数 |
| 実行履歴 | 90日間保持(コンソールで確認可) | CloudWatch Logsに出力 |
| 向いているユースケース | 長時間バッチ・人間の承認を含むフロー・決済処理 | 高頻度イベント処理・IoTデータ変換・ストリーミング処理 |
「とりあえずStandard」で始めておき、大量リクエストに対応する必要が出てきたらExpressへの切り替えを検討するのが現実的な進め方です。
基本的な使い方(コンソール操作・AWS CLI)
1. ステートマシンの作成(コンソール操作)
AWSコンソールにサインインし、Step Functionsサービスを開きます。東京リージョン(ap-northeast-1)を選択することを忘れずに。
・「ステートマシンを作成」をクリック
・「コードとビジュアルエディタを使用して記述」を選択
・「Standardワークフロー」を選択
・コードエディタにASL(上述のJSONサンプル)を貼り付け
・IAMロールを自動生成するか、事前に作成したロールを選択
・ステートマシン名を入力(例: order-processing-workflow)して「作成」をクリック
ビジュアルエディタがリアルタイムでフロー図を表示するので、JSONを編集しながら設計を確認できます。オンプレのジョブスケジューラーで設計図と実装コードが乖離しがちだった問題が、ここでは構造的に解消されています。
2. Lambda関数との連携
Step Functionsで最もよく使うのが、AWS Lambdaとの連携です。Task状態のResourceにLambda関数のARNを指定するだけで呼び出せます。
# Task状態でLambdaを呼び出す基本パターン { "Type": "Task", "Resource": "arn:aws:states:::lambda:invoke", "Parameters": { "FunctionName": "arn:aws:lambda:ap-northeast-1:123456789012:function:my-function", "Payload.$": "$" }, "ResultSelector": { "body.$": "$.Payload.body", "statusCode.$": "$.Payload.statusCode" }, "Next": "NextState" }
`Parameters` に `”Payload.$”: “$”` を指定すると、ステートマシンの入力データをそのままLambdaへ渡せます。`ResultSelector` でLambdaの戻り値から必要なフィールドのみを抽出し、次のステートへ引き渡す形が一般的です。
3. ワークフローの実行と確認
作成したステートマシンを選択し、「実行を開始」をクリックします。入力データ(JSON)を指定してスタートすると、コンソール上でリアルタイムに実行状況が確認できます。
・緑色のノード: 正常完了
・赤色のノード: 失敗
・青色のノード: 実行中
どのステップで止まっているかが一目でわかるため、オンプレ時代のように「ログを掘り続けてどのプロセスが死んでいるか探す」という作業が大幅に削減されます。
AWS CLIで実行する場合は以下のコマンドを使います。
# AWS CLI: ステートマシン実行開始 aws stepfunctions start-execution --state-machine-arn arn:aws:states:ap-northeast-1:123456789012:stateMachine:order-processing-workflow --name "exec-$(date +%Y%m%d%H%M%S)" --input '{"orderId": "ORD-001", "amount": 5000}' # 実行一覧を確認(実行中のものだけ) aws stepfunctions list-executions --state-machine-arn arn:aws:states:ap-northeast-1:123456789012:stateMachine:order-processing-workflow --status-filter RUNNING # 特定の実行の詳細を確認 aws stepfunctions describe-execution --execution-arn arn:aws:states:ap-northeast-1:123456789012:execution:order-processing-workflow:exec-20260607120000
エラーハンドリングとリトライ設計
Step Functionsの最大の強みのひとつが、エラーハンドリングを宣言的に記述できることです。オンプレで「リトライロジックを自前実装する」必要がなくなります。
1. Retry(リトライ)の設定
Task状態に `Retry` ブロックを追加するだけで、指定したエラーコードに対して自動リトライができます。
# Retry設定例(指数バックオフ付き) { "Type": "Task", "Resource": "arn:aws:states:::lambda:invoke", "Parameters": { "FunctionName": "arn:aws:lambda:ap-northeast-1:123456789012:function:call-external-api", "Payload.$": "$" }, "Retry": [ { "ErrorEquals": ["Lambda.ServiceException", "Lambda.AWSLambdaException"], "IntervalSeconds": 2, "MaxAttempts": 3, "BackoffRate": 2.0, "JitterStrategy": "FULL" }, { "ErrorEquals": ["States.Timeout"], "IntervalSeconds": 5, "MaxAttempts": 2, "BackoffRate": 1.5 } ], "Catch": [ { "ErrorEquals": ["States.ALL"], "Next": "HandleError", "ResultPath": "$.error" } ], "TimeoutSeconds": 30, "Next": "NextState" }
・`IntervalSeconds`: 最初のリトライまでの待機秒数
・`MaxAttempts`: 最大リトライ回数
・`BackoffRate`: リトライごとに待機時間を何倍にするか(指数バックオフ)
・`JitterStrategy`: “FULL”にするとバックオフにランダム揺らぎを加え、複数同時実行時のリトライ衝突を防ぐ
外部APIを呼び出すときや、一時的なスロットリングが起きやすいサービスを使うときに、この設定が特に効果を発揮します。
2. Catch(エラーキャッチ)による代替フロー
リトライを超えてもエラーが解決しない場合、`Catch` ブロックで別の状態へ遷移させます。上のサンプルでは、すべてのエラー(`States.ALL`)をキャッチして `HandleError` 状態へ遷移しています。
`ResultPath: “$.error”` を指定すると、元の入力データを保持したまま、エラー情報を `$.error` フィールドとして追加してHandleErrorへ渡せます。これにより、エラーハンドリング処理でオリジナルの入力データを参照できます。
`HandleError` では以下のような対応が取れます。
・SNSでアラートメールを担当者に送信
・エラー内容と入力データをDynamoDBに記録
・SQSのデッドレターキューに失敗メッセージを送る
・後続処理をスキップして安全に終了
3. waitForTaskTokenによる非同期待機
外部サービスの処理完了を待つ場合、`waitForTaskToken` パターンが有効です。
# waitForTaskTokenパターン(外部処理の完了待ち) { "Type": "Task", "Resource": "arn:aws:states:::lambda:invoke.waitForTaskToken", "Parameters": { "FunctionName": "arn:aws:lambda:ap-northeast-1:123456789012:function:async-processor", "Payload": { "taskToken.$": "$$.Task.Token", "data.$": "$" } }, "HeartbeatSeconds": 60, "TimeoutSeconds": 3600, "Next": "ProcessResult" }
このパターンでは、Lambda関数がタスクトークンを受け取り、外部処理(例: 動画エンコード・外部決済システム・人間の承認)が完了したタイミングで `SendTaskSuccess` または `SendTaskFailure` を呼び出します。それまでStep Functionsは待機状態を保持します。
# 外部処理完了後にStep Functionsへ通知(AWS CLI) aws stepfunctions send-task-success --task-token "受け取ったタスクトークン" --task-output '{"result": "completed", "outputPath": "s3://bucket/output.mp4"}' # 失敗の場合 aws stepfunctions send-task-failure --task-token "受け取ったタスクトークン" --error "ProcessingFailed" --cause "エンコード中にメモリ不足が発生"
`HeartbeatSeconds` は、外部処理が生きているかどうかを確認するためのタイムアウトです。この秒数以内に処理側から `SendTaskHeartbeat` を呼ばないと、ステートマシンはハートビートタイムアウトエラーとして扱います。
実務でよく使うアーキテクチャパターン
1. 注文処理ワークフロー(Eコマース典型例)
ECサイトの注文処理は、Step Functionsが最も得意とするユースケースのひとつです。
・Step 1 ValidateOrder: 入力データ検証・ユーザー認証確認
・Step 2 CheckInventory: 在庫確認(在庫不足→Choice→キャンセルフロー)
・Step 3 ProcessPayment: 決済処理(外部決済API呼び出し)
・Step 4 Choice: 決済成功→次へ / 失敗→補償処理→キャンセルフロー
・Step 5 ReserveInventory: 在庫引き当て
・Step 6 Parallel: 確認メール送信 + 物流システムへの通知を並列実行
・Step 7 Succeed: 正常完了
このフローをスクリプトで書くと、エラー時の補償トランザクション(在庫を戻す・決済を取り消す)の実装が複雑になります。Step Functionsではフロー図として全体が見渡せるため、設計ミスを事前に発見しやすくなります。
2. 画像・動画処理パイプライン(Mapステートの活用)
S3にアップロードされた複数の画像に対して同じ変換処理を適用するケースでは、Mapステートが役立ちます。
# Mapステートで画像リストを並列処理 { "Type": "Map", "ItemsPath": "$.imageList", "MaxConcurrency": 5, "Iterator": { "StartAt": "ResizeImage", "States": { "ResizeImage": { "Type": "Task", "Resource": "arn:aws:states:::lambda:invoke", "Parameters": { "FunctionName": "arn:aws:lambda:ap-northeast-1:123456789012:function:resize-image", "Payload.$": "$" }, "End": true } } }, "Next": "GenerateThumbnailIndex" }
`MaxConcurrency` で同時実行数を制御できるため、Lambdaの同時実行数制限やダウンストリームシステムへの負荷を調整しながら並列処理できます。`MaxConcurrency: 0` に設定すると、配列の全要素を可能な限り並列実行します。
3. 人間の承認を含むワークフロー
稟議承認や手動レビューが必要なフローでは、`waitForTaskToken` と組み合わせて実装します。
・管理者にメール送信(承認URLとタスクトークンをEmbedした状態)
・Step Functionsはそのまま最大1年間待機
・管理者がURLをクリックすると、Lambda経由でSendTaskSuccessを呼び出し
・ワークフローが再開し次のステップへ遷移
・タイムアウト設定により、一定時間内に承認がない場合はエスカレーション処理へ
オンプレでこれを実装しようとすると、ポーリング処理や状態管理DB、復旧時の再開ロジックなどを自前で作る必要がありました。Step Functionsはこれを数十行のASLで実現します。
料金の仕組み(コスト感覚)
Step Functionsの料金は、選択するワークフロータイプによって異なります(2026年3月時点、東京リージョン)。
| ワークフロータイプ | 課金単位 | 料金 |
|---|---|---|
| Standard | 状態遷移1,000回あたり | $0.025 |
| Express(同期) | リクエスト数 + GB秒 | $0.00001/リクエスト + $0.00001667/GB秒 |
| Express(非同期) | リクエスト数 + GB秒 | $0.000001/リクエスト + $0.00001667/GB秒 |
無料枠: Standardワークフローは毎月4,000回の状態遷移が無料。Expressワークフローは毎月100万リクエスト+300GB秒が無料です(12ヶ月の無料利用枠終了後も継続して対象)。
実際のコスト感(試算例)
月10,000回の注文処理ワークフロー(1回あたり平均8ステップ)を想定すると:
・状態遷移数: 10,000 × 8 = 80,000回
・無料枠を引いた遷移数: 80,000 – 4,000 = 76,000回
・月額: 76,000 / 1,000 × $0.025 = 約$1.90(280円程度)
Lambda関数の実行コストが別途かかりますが、Step Functions自体の料金は「動かしてみて驚くほど安い」という印象です。ただし、Expressで高頻度リクエストを処理する場合は、実行時間とリクエスト数を事前に試算してから選択することを推奨します。
よくあるトラブルと対処法
1. IAM権限エラー(最も多いつまずき)
Step FunctionsがLambdaやECS、SNS、DynamoDB等を呼び出すには、ステートマシンに割り当てるIAMロールに適切な権限が必要です。
よくあるエラーメッセージ: `States.TaskFailed: User: arn:aws:sts::… is not authorized to perform: lambda:InvokeFunction`
対処法としては、コンソールでステートマシンを作成する際に「新しいロールを自動的に作成」を選択すると、ASL内で使っているリソースに対応したポリシーが自動生成されます。後からLambdaやSNSトピックを追加した場合は、そのロールに対応するポリシーを手動で追加してください。
# ステートマシン用IAMポリシーの最小権限例 { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": ["lambda:InvokeFunction"], "Resource": "arn:aws:lambda:ap-northeast-1:123456789012:function:*" }, { "Effect": "Allow", "Action": ["sns:Publish"], "Resource": "arn:aws:sns:ap-northeast-1:123456789012:*" }, { "Effect": "Allow", "Action": [ "dynamodb:PutItem", "dynamodb:GetItem", "dynamodb:UpdateItem" ], "Resource": "arn:aws:dynamodb:ap-northeast-1:123456789012:table/my-table" } ] }
2. InputとOutputのデータ変換ミス
Step FunctionsではステートへのInput・タスクへのParameter・タスクのResult・次の状態へのOutputをそれぞれ制御できますが、慣れないうちは混乱しがちです。
・InputPath: ステートが受け取る入力データのどの部分を使うか(JSONPath指定)
・Parameters: タスクに渡すデータの形式を変換・整形
・ResultSelector: タスクの戻り値から使うフィールドを選択
・ResultPath: タスクの結果を入力データのどの位置にマージするか
・OutputPath: 次の状態へ渡すデータの絞り込み
デバッグには、Passステートを活用して「このステートに来たときのデータは何か」を確認するのが効果的です。Passステートに入力データが流れ込んだ時点のJSONを、実行履歴から確認できます。
3. Expressワークフローの実行履歴が見えない
Expressワークフローはコンソールで実行履歴を確認できません。デバッグ時は必ずCloudWatch Logsへのログ出力を有効化しておく必要があります。
・ステートマシン作成時に「ログレベル」を「ALL」に設定
・ロググループ名(例: `/aws/states/my-express-workflow`)をあらかじめ決めておく
・`aws logs filter-log-events –log-group-name /aws/states/my-express-workflow` でCLIからも確認可能
・Standardワークフローに切り替えてデバッグし、確認後にExpressに戻す方法も有効
4. Lambdaタイムアウト(15分制限)を超える処理
Lambdaには最大15分のタイムアウト制限があります。それを超える処理が必要な場合は以下の選択肢があります。
・ECS Fargate Taskを使う: 長時間処理をFargateコンテナに委ねる(ECSタスクのリソースARNをTaskステートで指定可能)
・AWS Batchを使う: バッチ処理に特化したサービスで数時間~数日の処理に対応
・waitForTaskTokenで非同期化: Lambda内で非同期処理を開始し、完了後にSendTaskSuccessを呼ぶ設計に変更
・Mapステートで分割: 大きな処理を小さな単位に分割して並列実行し、各ユニットを15分以内に収める
オンプレ経験者が押さえておくべき設計思想の違い
Sagaパターンによる分散トランザクション管理
マイクロサービス環境では、複数のサービスにまたがるトランザクション管理が難しくなります。オンプレでは「2相コミット」でDB間の整合性を担保できましたが、クラウドでは各サービスが独立したDBを持つため、同じアプローチが取れません。
Step Functionsを使ったSagaパターンでは、各ステップの補償処理(ロールバック処理)をCatchブロックで定義することで、分散トランザクションを安全に扱えます。
・決済処理が成功したが在庫引き当てが失敗した場合 → Catchで決済をキャンセル(補償処理)
・補償処理自体が失敗するケースにも備えてRetryを設定
・補償処理のCatchで最終的なFail状態へ遷移し、アラートを発報
Catchチェーンで補償処理のフローを宣言的に書けるため、「何かエラーが起きたとき何が保証されるか」が設計図として残ります。スクリプトでロールバックロジックを管理していた時代とは、可読性・保守性が大きく異なります。
イベント駆動との組み合わせ
Step FunctionsはAmazon EventBridgeと組み合わせることで、イベント駆動型のワークフロー起動が実現できます。
・S3にファイルがアップロードされた → EventBridgeがStep Functionsを起動 → 変換パイプライン実行
・DynamoDB Streamsのレコード変更 → EventBridge Pipes → Step Functionsで後処理
・定期実行のバッチ → EventBridge Scheduler → Step Functions起動
AWS EventBridgeの詳細については、クラウドマスターズ.TOKYOの関連記事「AWS EventBridge入門|イベント駆動アーキテクチャの基礎からルール設計・スケジューラーまで現場で使える実践ガイド」も参照してください。
Linuxサーバーの基礎については、姉妹サイトLinuxMaster.JPで詳しく解説しています。EC2上でのサーバー構築・運用を学びたい方はぜひ参照してください。
本記事のまとめ
AWS Step Functionsの主要ポイントを整理します。
| 項目 | ポイント |
|---|---|
| 概念 | ステートマシンでワークフローをJSON(ASL)として定義・管理 |
| 種別選択 | 長時間・正確性重視→Standard / 高頻度・短時間→Express |
| エラー対処 | Retry(指数バックオフ+Jitter)+ Catch(補償フロー)の組み合わせ |
| よく使うパターン | Lambda連携 / Mapで並列 / waitForTaskTokenで非同期待機 / Sagaパターン |
| コスト感 | Standard: $0.025/1,000遷移、毎月4,000遷移まで無料(東京リージョン) |
| 注意点 | IAMロール設定 / I/Oデータ変換の理解 / Expressのログ出力設定 |
オンプレ時代に「スクリプトのif地獄」「ジョブスケジューラーのブラックボックス」に悩まされてきたエンジニアにとって、Step Functionsは発想の転換を促してくれるサービスです。「処理の流れを設計図として管理する」という考え方が、マイクロサービス時代のワークフロー管理の基本になります。まず小さなLambda連携ワークフローから試してみることをお勧めします。
ワークフロー設計の”次の一手”に迷っていませんか?
Step Functionsを使いこなすには、Lambda・SQS・EventBridgeとの連携パターンを体系的に理解することが近道です。
オンプレの経験を活かしながら、現場で使えるクラウドスキルを体系的に身につけたい方へ、メルマガで実践的なクラウド活用ノウハウをお届けしています。
