ステートマシンとステート
まずはAWS Step Functionsを理解するにあたっての基礎概念となるのがステートマシンです。以下がビジュアライズされたステートマシンとなりますがひとかたまりのワークフローを定義したものがステートマシンになると理解しておけばよいでしょう。そして、ステートマシンはステート(状態)の集まりで構成されます。ここに様々なAWSサービスとそのアクションや条件分岐などを定義していきます。AWSマネジメントコンソールからGUIベースでワークフローを定義することができるので、まずはこれを試して見るのが良いでしょう。
ステートにはAWSサービスだけでなくAWS Step Functionsで定義されているフロー制御も設定することが可能です。以下がステートに設定することができる制御内容の一覧です。これらを組み合わせることでワークフローを構築します。
State Type | 説明 |
---|---|
Task | 特定の作業を実行するステート(例: Lambda関数を呼び出す) |
Choice | 条件分岐を処理するステート |
Parallel | 並列処理を実行するステート |
Map | 並列でのMap処理を実行するステート |
Pass | 処理をそのまま出力へ渡すステート |
Wait | 一定の時間、処理を待機するステート |
Fail | ワークフローを失敗として終了するステート |
Succeed | ワークフローを成功として処理するステート |
Amazon States Languageによるワークフローの定義
Amazon States Language(ASL)は、AWS Step Functionsでステートマシンを定義するためのJSONベースの構造化言語です。上記ビジュアライズされたワークフローは内部的にはこのASLによって定義されています。例えば以下がASLで記述されたワークフローの一部になりますが、かなり複雑で正直覚えたくないというのが本音でしょう。現状では、GUIからワークフローを定義してそこからASLのコードをエクスポートすることも出来ます。それをCDKから読み込んでデプロイするといったことも可能になったので、昔に比べてだいぶ実装自体はやりやすくなりました。
{
"StartAt": "FindRootUserEmail",
"States": {
"FindRootUserEmail": {
"Type": "Task",
"Resource": "arn:aws:lambda:us-east-1:xxxxxxxx:function:rpa-dev-FindRootUserEmail",
"Next": "RequestPasswordReset",
"Catch": [
{
"ErrorEquals": [
"States.ALL"
],
"Next": "FailedState"
}
]
},
"RequestPasswordReset": {
"Type": "Task",
"Resource": "arn:aws:lambda:us-east-1:xxxxxxxx:function:rpa-dev-RequestPasswordReset",
"Next": "WaitOneMinutes",
"Catch": [
{
"ErrorEquals": [
"States.ALL"
],
"Next": "FailedState"
}
]
}
エラーハンドリング
AWS Step Functionsの特徴の一つとしてエラー時の処理が非常に柔軟というのがあります。リトライの条件やエラー時に専用のステートに飛ばすと言ったことが非常にやりやすく、これはビジネスにクリティカルなワークフローでは必須でしょう。
例えばワークフロー内のAWS Lambdaで特定のExceptionが発生した際には以下のような記述を行なうことでLambdaファンクションのリトライを行ってくれます。
"Retry": [
{
"ErrorEquals": [
"Lambda.ServiceException"
],
"IntervalSeconds": 2,
"MaxAttempts": 6,
}
]
また、Catchブロックを使用することでエラー時には特定のステートに遷移させることが可能となります。例えばECサイトなどで在庫の確保処理が成功したにも関わらず後のステートで決済に失敗した場合には、Catchブロックで在庫確保の取り消しを行うステートに遷移させる必要があるでしょう。
"Catch": [
{
"ErrorEquals": [
"States.ALL"
],
"Next": "Error Handling"
}
]
StandardモードとExpressモード
AWS Step Functionsでステートマシンを作る場合にはStandardモードとExpressモードの2パターンの中から一つを選ぶ必要があります。以下にその違いをまとめました。
項目 / カテゴリー | Standard Workflows | Express Workflows |
---|---|---|
最大継続時間 | 1年 | 5分 |
実行開始レート | APIアクションのスロットリング制限を参照 2024年9月現在: バケットサイズ800-1300、リフィルレート150-300/s | APIアクションのスロットリング制限を参照 2024年9月現在: バケットサイズ6000、リフィルレート6000/s |
状態遷移レート | 状態スロットリング制限を参照 2024年9月現在: バケットサイズ800-5000、リフィルレート800-5000/s | 制限なし |
料金 | 状態遷移ごとに課金 | 実行回数、実行時間、メモリに基づいて課金 |
実行履歴 | API、コンソール、CloudWatch Logsを通じて表示・説明・デバッグ可能 | 5分以内の無制限履歴、コンソールとCloudWatch Logsでデバッグ |
実行の意味論 | 1回のみ正確に実行 | 非同期: 最低1回実行、同期: 最大1回実行 |
サービス統合 | すべての統合とパターンに対応 | すべての統合に対応(Job-run (.sync) や Callback (.waitForTaskToken) を除く) |
分散マップ | 対応 | 未対応 |
アクティビティ | 対応 | 未対応 |
Standardモードは、長時間実行可能で、耐久性があるアプリケーション向けに設計されています。一度作成したステートマシンの種類は変更できません。したがって、ワークフローを設定する際には、StandardかExpressモードのどちらが必要かを慎重に検討する必要があります。Standardモードは、一回のみ正確に処理されることを保証しており、リトライや失敗が発生しても、ワークフロー内の各ステップが正確に一度だけ実行されることを確実にします。
これは、データの一貫性と信頼性が不可欠なアプリケーションにとって特に重要です。たとえば、各トランザクションが正確に一度だけ処理される必要がある金融取引処理システム、予約システムや決済システムなどはStandardモードが適しています。さらに、Standardモードは、数時間から数日、さらには数ヶ月にわたる長時間のプロセスにも最適です。
Expressモードは、高ボリューム、短期間、コスト重視のアプリケーション向けに設計されており、高速な状態管理を必要とします。Expressモードは、高スループットかつ低レイテンシな処理に最適化されており、スピードとコスト効率が重要なアプリケーションに最適です。Standardモードとは異なり、Expressモードは正確に1回の処理を保証するのではなく、少なくとも1回の処理を提供します。これは、時折重複した実行が許容されるシナリオに適しています。
すなわち、もし各ステップが冪等性を持たなければ、Expressモードを使用することはできません。同じIDを持つ2つのステートマシンがほぼ同時に開始されることがあります。アプリケーションがこれを許容できない場合、Expressモードは有効な選択肢ではありません。このあたりの考え方は非同期モードで実行されるAWS Lambdaと同じですね。
Expressモードは高いスケーラビリティを備えており、1秒あたり数千件の実行を処理できます。このスケーラビリティにより、トラフィックの急激な増加に対してもパフォーマンスを損なうことなく対応することができます。なので、IoTなどのリアルタイムのデータ処理システムでは、Expressモードを使用して、入ってくるデータストリームを処理し、変換を行い、結果をほぼリアルタイムで保存することができます。
まとめ
今回はAWS Step Functionsの基礎概念についてまとめてみました。Step Functionsを使いこなすためにはStep Functions独自の仕様や制約を理解したうえで実装を行う必要がありますが幅広いワークフローのユースケースに対応できる柔軟なサービスです。ビジュアル化されたワークフローはチームでの開発を行う際にもその認知負荷を下げ、メンテナンスをやりやすいものにしてくれるでしょう。是非、使い方を覚えてサーバレス開発の一つのオプションとして覚えておけば様々なケースにうまく対応していくことができるでしょう。