Step Functions のベストプラクティス - AWS Step Functions

Step Functions のベストプラクティス

ステートの管理とデータの変換

以下のトピックは、Step Functions ワークフローの管理と最適化に役立つベストプラクティスです。

Express ワークフローを使用したコストの最適化

Step Functions は、ステートマシンの構築に使用するワークフロータイプに基づいて、標準ワークフローと Express ワークフローの価格を決定します。サーバーレスワークフローのコストを最適化するには、以下の推奨事項のどちらかまたは両方に従ってください。

Standard または Express ワークフロータイプの選択が請求にどのように影響するかについては、「AWS Step Functions の料金」を参照してください。

Standard ワークフローでの Express ワークフローのネスト

Step Functions は一定の期間とステップ数のあるワークフローを実行します。ワークフローによっては、短時間待機した後に実行を完了する場合があります。また、長時間実行されるワークフローとイベントレートの高いワークフローの両方を組み合わせなければならない場合があります。Step Functions を使用すると、小さくて単純な複数のワークフローから大規模で複雑なワークフローを構築できます。

例えば、注文処理ワークフローを構築する場合、同一ではないすべてのアクションを標準ワークフローに含めることができます。これには、人が操作する注文の承認や支払いの処理などのアクションが含まれる場合があります。その後、支払い通知の送信や商品在庫の更新など、一連の独立したアクションを Express ワークフローにまとめることができます。この Express ワークフローは標準ワークフロー内にネストできます。この例で、標準ワークフローは親ステートマシンと呼ばれます。ネストされた Express ワークフローは子ステートマシンと呼ばれます。

Standard ワークフローから Express ワークフローへの移行

次の要件を満たしている場合は、Standard ワークフローから Express ワークフローへの移行を検討する必要があります。

  • ワークフローは 5 分以内に実行を完了する必要があります。

  • ワークフローが at-least-once 実行モデルに準拠している (各ステップの 1 回以上の実行が許可される) 必要があります。

  • ワークフローは .waitForTaskToken または .sync サービス統合パターンを使用しません

重要

Express ワークフローは Amazon CloudWatch Logs を使用して実行履歴を記録します。CloudWatch Logs を使用すると、追加のコストが発生します。

コンソールを使用して Standard ワークフローを Express ワークフローに移行するには
  1. Step Functions コンソールを開きます。

  2. [ステートマシン] ページで、標準タイプのステートマシンを選択して開きます。

    ヒント

    [すべてのタイプ] ドロップダウンリストから [標準] を選択すると、ステートマシンのリストがフィルタリングされ、標準ワークフローのみが表示されます。

  3. [新規にコピー] を選択します。

    デザインモード で Workflow Studio が開き、選択したステートマシンのワークフローが表示されます。

  4. (オプション) ワークフローのデザインを更新します。

  5. ステートマシンの名前を指定します。これを行うには、MyStateMachine のデフォルトステートマシン名の横にある編集アイコンを選択します。次に、[ステートマシンの設定][ステートマシン名] ボックスに名前を指定します。

  6. (オプション) [ステートマシンの設定] で、ステートマシンのタイプや実行ロールなど、他のワークフロー設定を指定します。

    [タイプ] では必ず [Express] を選択してください。[ステートマシンの設定] のその他のデフォルト設定をすべてそのまま使用します。

    注記

    以前 AWS CDK または AWS SAM で定義された Standard ワークフローを移行する場合は、Type の値と Resource の名前を変更する必要があります。

  7. [ロールの作成を確認] ダイアログボックスで、[確認] を選択して続行します。

    [ロールの設定を表示] を選択して [ステートマシンの設定] に戻ることもできます。

    注記

    Step Functions が作成した IAM ロールを削除すると、Step Functions を後で再作成することはできません。同様に、ロールを変更すると (例えば、IAM ポリシーのプリンシパルから Step Functions を削除するなど)、後で Step Functions でそれを元の設定に復元することはできません。

ワークフローのコスト最適化を管理する際のベストプラクティスとガイドラインについて詳しくは、「Building cost-effective AWS Step Functions workflows」を参照してください。

Step Functions でのステートマシンとアクティビティのタグ付け

AWS Step Functions は、ステートマシン (Standard と Express の両方) とアクティビティのタグ付けをサポートしています。タグにより、リソースを追跡して管理したり、AWS Identity and Access Management (IAM) ポリシーのセキュリティを向上させることができます。Step Functions リソースにタグ付けした後、AWS Resource Groups で管理できます。方法については、「AWS Resource Groups ユーザーガイド」を参照してください。

次の例のように、タグベースの認可の場合、ステートマシンの実行リソースはステートマシンに関連付けられたタグを継承します。

arn:partition:states:region:account-id:execution:<StateMachineName>:<ExecutionId>

実行リソース ARN を指定する DescribeExecution またはその他の API を呼び出すとき、Step Functions はタグベースの認可を実行しながら、ステートマシンに関連付けられたタグを使用してリクエストを許可または拒否します。これにより、ステートマシンレベルの実行へのアクセスを許可または拒否できます。

リソースのタグ付けに関連する制限を確認するには、タグ付けに関連する制限 を参照してください。

コスト割り当てのタグ付け

コスト配分タグを使用すると、ステートマシンの目的を特定し、その組織を AWS 請求に反映できます。サインアップして AWS アカウントの請求書にタグキーおよび値を含めます。レポートの設定についての詳細は、「AWS Billing ユーザーガイド」の「Setting Up a Monthly Cost Allocation Report」を参照してください。

例えば、次のようにコストセンターと Step Functions リソースの目的を表すタグを追加できます。

リソース キー
StateMachine1 Cost Center 34567
Application Image processing
StateMachine2 Cost Center 34567
Application Rekognition processing

セキュリティのためのタグ付け

IAM は、タグに基づくリソースへのアクセスの制御をサポートしています。タグに基づいてアクセスを制御するには、IAM ポリシーの条件要素でリソースタグに関する情報を提供します。

例えば、キー environment および値 production のタグを含むすべての Step Functions リソースへのアクセスを制限できます。

{ "Version":"2012-10-17", "Statement": [ { "Effect": "Deny", "Action": [ "states:TagResource", "states:DeleteActivity", "states:DeleteStateMachine", "states:StopExecution" ], "Resource": "*", "Condition": { "StringEquals": {"aws:ResourceTag/environment": "production"} } } ] }

詳細については、IAM ユーザーガイドの [Controlling Access Using Tags] (タグを使用したアクセス制御) を参照してください。

Step Functions コンソールでのタグの管理

Step Functions コンソールでステートマシンのタグを表示および管理できます。ステートマシンの [Details] (詳細) ページから、[Tags] (タグ) を選択します。

Step Functions API アクションを使用したタグの管理

Step Functions API を使用してタグを管理するには、次の API アクションを使用します。

タイムアウトを使用して Step Functions ワークフローの実行のスタックを回避する

デフォルトでは、Amazon States Language はステートマシンの定義にタイムアウトを指定しません。明示的なタイムアウトが設定されていないと、Step Functions は多くの場合、アクティビティのワーカーからのレスポンスでしか、タスクが完了したことを知ることができません。エラーが発生した場合、TimeoutSeconds フィールドに Activity 状態または Task 状態が指定されていないと、実行は、返されることのないレスポンスを待ち続けるため、スタックします。

この状況を回避するには、ステートマシンで Task を作成するときに、適切なタイムアウトを指定します。例:

"ActivityState": { "Type": "Task", "Resource": "arn:aws:states:region:account-id:activity:HelloWorld", "TimeoutSeconds": 300, "Next": "NextState" }

タスクトークン (.waitForTaskToken) でコールバックを使用する場合は、ハートビートを使用して Task 状態定義に HeartbeatSeconds フィールドを追加することを推奨します。HeartbeatSeconds をタスクのタイムアウトよりも短く設定できるので、ワークフローがハートビートエラーで失敗した場合、タスクが完了するまでに時間がかかったのではなく、タスクの失敗が原因であることがわかります。

{ "StartAt": "Push to SQS", "States": { "Push to SQS": { "Type": "Task", "Resource": "arn:aws:states:::sqs:sendMessage.waitForTaskToken", "HeartbeatSeconds": 600, "Parameters": { "MessageBody": { "myTaskToken.$": "$$.Task.Token" }, "QueueUrl": "https://sqs.us-east-1.amazonaws.com/account-id/push-based-queue" }, "ResultPath": "$.SQS", "End": true } } }

詳細については、Amazon States Language ドキュメントの Task ワークフロー状態 を参照してください。

注記

Amazon States Language の定義の TimeoutSeconds フィールドを使用してステートマシンのタイムアウトを設定できます。詳細については、「Step Functions ワークフローの Amazon States Language でのステートマシン構造」を参照してください。

Step Functions で大きなペイロードを渡す代わりに Amazon S3 の ARN を使用する

状態間でデータの大きいペイロードを渡す実行を終了できます。ステートの間で渡すデータが 256 KiB を超える場合、Amazon Simple Storage Service (Amazon S3) を使用してデータを保存し、バケット名とキーバリューを取得するため、Payload パラメータでバケットの Amazon リソースネーム (ARN) を解析します。または、実行時に小さいペイロードを渡すように実装を調整します。

次の例では、ステートマシンは Amazon S3 バケットの JSON ファイルを処理する AWS Lambda 関数に入力を渡しています。このステートマシンを実行すると、Lambda 関数は JSON ファイルの内容を読み取り、ファイルの内容を出力として返します。

Lambda 関数を作成する

pass-large-payload という名前の次の Lambda 関数は、特定の Amazon S3 バケットに保存されている JSON ファイルの内容を読み取ります。

注記

この Lambda 関数を作成したら、必ず、その IAM ロールに Amazon S3 バケットから読み取るための適切なアクセス許可を付与してください。例えば、Lambda 関数のロールに AmazonS3ReadOnlyAccess のアクセス許可をアタッチします。

import json import boto3 import io import os s3 = boto3.client('s3') def lambda_handler(event, context): event = event['Input'] final_json = str() s3 = boto3.resource('s3') bucket = event['bucket'].split(':')[-1] filename = event['key'] directory = "/tmp/{}".format(filename) s3.Bucket(bucket).download_file(filename, directory) with open(directory, "r") as jsonfile: final_json = json.load(jsonfile) os.popen("rm -rf /tmp") return final_json
ステートマシンを作成する

次のステートマシンは、以前に作成した Lambda 関数を呼び出します。

{ "StartAt":"Invoke Lambda function", "States":{ "Invoke Lambda function":{ "Type":"Task", "Resource":"arn:aws:states:::lambda:invoke", "Parameters":{ "FunctionName":"arn:aws:lambda:us-east-2:123456789012:function:pass-large-payload", "Payload":{ "Input.$":"$" } }, "OutputPath": "$.Payload", "End":true } } }

大量のデータを入力で渡すのではなく、そのデータを Amazon S3 バケットに保存し、Payload パラメータでバケットの Amazon リソースネーム (ARN) を解析して、バケット名とキーバリューを取得します。Lambda 関数はその ARN を使用してデータに直接、アクセスできます。次に示しているステートマシン実行の入力例では、データが amzn-s3-demo-large-payload-json という名前の Amazon S3 バケット内の data.json に保存されています。

{ "key": "data.json", "bucket": "arn:aws:s3:::amzn-s3-demo-large-payload-json" }

Step Functions で履歴クォータに到達しないように新しい実行を開始する

AWS Step Functions のイベント履歴には、25,000 エントリのハードクォータがあります。実行イベントが 24,999 件に達すると、次のイベントが発生するまで待機します。

  • イベント番号 25,000 が ExecutionSucceeded の場合、実行は正常に終了します。

  • イベント番号 25,000 が ExecutionSucceeded 以外の場合、ExecutionFailed イベントはログに記録され、履歴の上限に達したためステートマシンの実行は失敗します。

長時間の実行でこのクォータに達しないようにするには、次のいずれかの方法を試行できます。

Lambda サービスの一時的な例外の処理

AWS Lambda では、サービスエラーが発生することがあります。この場合、Lambda を呼び出すと、ClientExecutionTimeoutExceptionServiceExceptionAWSLambdaException、または SdkClientException などの 500 エラーが生じます。ベストプラクティスとしては、Lambda 関数を呼び出す Retry、あるいはエラーを Catch するために、ステートマシンでのこのような例外を事前に処理します。

Lambda エラーは、Lambda.ErrorName として報告されます。Lambda サービス例外エラーを再試行するには、次の Retry コードを使用します。

"Retry": [ { "ErrorEquals": [ "Lambda.ClientExecutionTimeoutException", "Lambda.ServiceException", "Lambda.AWSLambdaException", "Lambda.SdkClientException"], "IntervalSeconds": 2, "MaxAttempts": 6, "BackoffRate": 2 } ]
注記

Lambda ランタイムの未処理のエラーは、以前は Lambda.Unknown としてのみ報告されていました。新しいランタイムでは、タイムアウトはエラー出力で Sandbox.Timedout として報告されます。

Lambda が最大呼び出し回数を超えると、報告されるエラーは Lambda.TooManyRequestsException となります。

Lambda.UnknownSandbox.TimedoutStates.TaskFailed で照合して、考えられるエラーを処理します。States.ALL も使用できますが、単独で、かつリストの最後に記述する必要があります。

Lambda HandledUnhandled エラーの詳細については、AWS Lambda デベロッパーガイドFunctionError を参照してください。

詳細については次を参照してください:

アクティビティタスクのポーリング時のレイテンシーを回避する

GetActivityTask API は、taskToken1 回のみ提供するように設計されています。アクティビティワーカーと通信している間に taskToken がドロップされた場合、GetActivityTask がタイムアウトするまで、レスポンスの待機のため複数の GetActivityTask リクエストが 60 秒ブロックされます。

レスポンス待ちのポーリングが少数しかない場合、ブロックされたリクエストの後ろにすべてのリクエストが追加され、停止する可能性があります。ただし、各アクティビティ Amazon リソースネーム (ARN) に多数の未処理のポーリングがあり、リクエストの一部が待機中のままになる場合、taskToken を取得して処理の実行を開始するリクエストがさらにたくさんあります。

本番稼働用システムでは、それぞれのアクティビティ ARN の各時点で少なくとも 100 のオープンポーリングを推奨します。1 つのポーリングがブロックされ、それらのポーリングの一部がその後ろに並んでいる場合、taskToken のリクエストがブロックされている間に処理を実行するための GetActivityTask を受け取るさらに多くのリクエストがあります。

タスクのポーリング時に、これらのレイテンシーの問題を回避する方法。

  • アクティビティワーカーの実装の作業とは別のスレッドとしてポーラーを実装します。

  • 各時点でのアクティビティ ARN あたり、少なくとも 100 のオープンポーリングが必要です。

    注記

    ARN あたり 100 のオープンポーリングにスケーリングすると、コストが高くなる可能性があります。例えば、ARN あたり 100 の Lambda 関数でポーリングする場合、1 つの Lambda 関数で 100 のポーリングスレッドを実行するよりも 100 倍コストが高くなります。レイテンシーを短縮しながらコストを最小限に抑えるには、非同期 I/O を使用する言語により、ワーカーごとに複数のポーリングスレッドを実装します。ポーラースレッドとワークスレッドが異なるアクティビティワーカーの例については、例: Ruby のアクティビティワーカー を参照してください

アクティビティおよびアクティビティワーカーの詳細については、Step Functions のアクティビティについて を参照してください

CloudWatch Logs リソースポリシーのサイズ制限の回避

ログでステートマシンを作成する場合、または既存のステートマシンのログ記録を有効にするよう更新する場合、Step Functions は、指定したロググループで CloudWatch Logs リソースポリシーを更新する必要があります。CloudWatch Logs リソースポリシーは 5,120 文字に制限されています。

CloudWatch Logs でポリシーがサイズ制限に近づいていることが検出されると、CloudWatch Logs は /aws/vendedlogs/ でスタートするロググループのログ記録を自動的に有効にします。

CloudWatch Logs リソースポリシーのサイズ制限に達しないようにするには、CloudWatch Logs ロググループ名の先頭に /aws/vendedlogs/ というプレフィックスを付けます。Step Function コンソールでロググループを作成すると、推奨されるロググループ名には既に /aws/vendedlogs/states のプレフィックスが付いています。

また、CloudWatch Logs には、リージョンごと、アカウントごとに 10 のリソースポリシーのクォータもあります。アカウントのリージョンに既に 10 個の CloudWatch Logs リソースポリシーがあるステートマシンでログ記録を有効にしようとすると、ステートマシンは作成または更新されません。ログ記録に関するクォータの詳細については、「CloudWatch Logs のクォータ」を参照してください。

CloudWatch Logs へのログの送信に問題がある場合は、「Troubleshooting state machine logging to CloudWatch Logs」を参照してください。