失敗したステップを再試行して永続的なエラーを処理する

AWSBeginner
オンラインで実践に進む

はじめに

依存先の一時的な失敗は復旧する場合がありますが、無効な注文は失敗したままにすべきです。選択的な再試行と永続的な失敗の経路を設定し、実際の試行と保存された結果を観察します。

先に 複数ステップの注文ワークフローを構築する を完了してください。この新しい VM は、独自のワーカーと空のテーブルを提供します。以前のステートマシン、ロール、実行は再利用しません。

認定試験との関連

このラボでは、次の試験トピックに関連する実践的な演習を行います。

ワークフローによるワーカー呼び出しを認可する

このステップでは、提供された業務ワーカーを確認し、Step Functions 用の独立した実行ロールを作成します。

Terminal の隣で AWS View を使い、CLI クエリをこのラボの実際のリソースと結果と比較します。提供された参照データを保持してください。

この新しい VM は、ワーカー関数と独立した注文・診断・参照テーブルを提供します。ステートマシンやワークフローロールはまだありません。ワーカーは注文を受け取り、数量と合計を書き込み、後でサマリーを読み取れます。合成障害のテストでは、flaky モードが最初の試行で業務書き込み前に TransientOrderError を発生させ、permanent モードが書き込み前に InvalidOrder を発生させます。診断用の試行記録は業務注文とは別です。Lambda 実行ロールは、ワークフロー自体の操作とは別の、これらのテーブル操作をすでに認可しています。

プロジェクトディレクトリから始めます。シェルの代入は返された識別子を保存します。--query はレスポンスフィールドを選択し、--output text は再利用可能な文字列を生成します。

cd /home/labex/project
WORKER_NAME=labex-ev04-worker
WORKER_ARN=$(aws lambda get-function-configuration \
  --function-name labex-ev04-worker \
  --query FunctionArn \
  --output text)
aws lambda get-function-configuration \
  --function-name labex-ev04-worker \
  --query '{Name:FunctionName,Role:Role,Runtime:Runtime,Timeout:Timeout}'
aws stepfunctions list-state-machines

ワーカーは Python3.12 と独自の Lambda ロールを使い、ステートマシン一覧は空です。Step Functions には自身の実行ロールが必要です。信頼ポリシーは Step Functions サービスによるそのロールの引き受けを許可し、権限ポリシーは、生成されたセッションがこのワーカーだけを呼び出すことを許可します。引用符付きのヒアドキュメントは JSON をそのまま書き込み、file:// はそれをリクエストに読み込みます。

cat > workflow-trust.json <<'JSON'
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Service": "states.amazonaws.com"
      },
      "Action": "sts:AssumeRole"
    }
  ]
}
JSON
ROLE_ARN=$(aws iam create-role \
  --role-name labex-ev04-workflow-role \
  --assume-role-policy-document file://workflow-trust.json \
  --query Role.Arn \
  --output text)

通常の権限ドキュメントを書き込みます。シェルは $WORKER_ARN を挿入し、この権限付与を提供されたワーカーに限定します。

cat > workflow-invoke.json <<EOF
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": "lambda:InvokeFunction",
      "Resource": "$WORKER_ARN"
    }
  ]
}
EOF
aws iam put-role-policy \
  --role-name labex-ev04-workflow-role \
  --policy-name InvokeWorker \
  --policy-document file://workflow-invoke.json
aws iam get-role-policy --role-name labex-ev04-workflow-role --policy-name InvokeWorker

ポリシーには 1 つの正確な関数 ARN があります。Step Functions はワーカーの DynamoDB 権限を受け取りません。ワーカーは独立した Lambda ロールでそれらの呼び出しを行います。認可の検証を実行してください。

回数を限定した再試行と永続的な失敗の経路を設定する

このステップでは、選択的な復旧動作を持つ、実際の 2 タスクのワークフローを構築します。

一時的な失敗の再試行と永続的な失敗

このワーカーの一時的なエラーは再試行で復旧できます。永続的なエラーは Catch を通り、明示的な失敗結果になります。

ASL の Retry は、再試行できるタスクエラーを列挙します。ErrorEquals は関数のエラー型に一致する必要があります。IntervalSeconds:1 は 1 秒の遅延から始め、BackoffRate:2 は次の遅延を倍にします。MaxAttempts:2 は、最初の試行後に最大 2 回の再試行を許可します。この再試行は、あらゆる失敗ではなく、TransientOrderError だけを扱います。

Catch は、タスクが復旧できなかったエラーに対して、別の状態を選択します。ResultPath はエラーを failure の下に記録し、Next は明示的な Fail 状態へ進みます。エラーを処理したからといって、業務ジョブが成功したとは限りません。永続的な InvalidOrder は、注文を完了したふりをせず、OrderRejected を伴う FAILED で終了します。

引用符付きのヒアドキュメントは JSON をそのまま書き込みます。既存の Choice は正ではない数量を拒否します。2 つの Task は、保存とその後のサマリー読み取りを行います。Payload.$ は現在の入力を渡し、ResultSelector は実際の関数ペイロードを保持し、ResultPath はそれを saved の下に保存し、OutputPath は実際のサマリーを返します。

cat > workflow-template.json <<'JSON'
{
  "StartAt": "CheckQuantity",
  "States": {
    "CheckQuantity": {
      "Type": "Choice",
      "Choices": [
        {
          "Variable": "$.quantity",
          "NumericGreaterThan": 0,
          "Next": "StoreOrder"
        }
      ],
      "Default": "Rejected"
    },
    "StoreOrder": {
      "Type": "Task",
      "Resource": "arn:aws:states:::lambda:invoke",
      "Parameters": {
        "FunctionName": "WORKER_NAME",
        "Payload.$": "$"
      },
      "ResultSelector": {
        "result.$": "$.Payload"
      },
      "ResultPath": "$.saved",
      "Retry": [
        {
          "ErrorEquals": [
            "TransientOrderError"
          ],
          "IntervalSeconds": 1,
          "BackoffRate": 2,
          "MaxAttempts": 2
        }
      ],
      "Catch": [
        {
          "ErrorEquals": [
            "InvalidOrder"
          ],
          "Next": "Rejected",
          "ResultPath": "$.failure"
        }
      ],
      "Next": "ReadSummary"
    },
    "ReadSummary": {
      "Type": "Task",
      "Resource": "arn:aws:states:::lambda:invoke",
      "Parameters": {
        "FunctionName": "WORKER_NAME",
        "Payload": {
          "stage": "summary",
          "id.$": "$.saved.result.id"
        }
      },
      "OutputPath": "$.Payload",
      "End": true
    },
    "Rejected": {
      "Type": "Fail",
      "Error": "OrderRejected",
      "Cause": "Order could not be completed"
    }
  }
}
JSON
jq --arg worker "$WORKER_NAME" '.States.StoreOrder.Parameters.FunctionName=$worker | .States.ReadSummary.Parameters.FunctionName=$worker' workflow-template.json > workflow.json
MACHINE_ARN=$(aws stepfunctions create-state-machine \
  --name labex-ev04-orders \
  --type STANDARD \
  --role-arn "$ROLE_ARN" \
  --definition file://workflow.json \
  --query stateMachineArn \
  --output text)
aws stepfunctions describe-state-machine \
  --state-machine-arn "$MACHINE_ARN" \
  --query '{Name:name,Definition:definition}'

定義には、選択的な retry と catch のブロックが含まれます。AWS View にも同じ設定が表示され、実行や業務注文はまだありません。復旧定義の検証を実行してください。

実際の Retry、Catch、権限の結果を観察する

このステップでは、一時的な失敗、永続的な失敗、拒否される呼び出しを実行します。

ワーカーの最初の flaky 試行は、診断用試行カウンターを更新し、注文を書き込む前にエラーを発生させます。次の試行は成功できます。回数を限定したシェルループは、実行中でなくなるまで 2 秒ごとに状態を読み取ります。$(...) は出力を取得し、break はループを終了します。ループ後も実行が RUNNING の場合は、先へ進む前に確認してください。

RETRY_ARN=$(aws stepfunctions start-execution \
  --state-machine-arn "$MACHINE_ARN" \
  --name retry-order \
  --input '{"id":"retry-order","quantity":2,"mode":"flaky"}' \
  --query executionArn \
  --output text)
for attempt in $(seq 1 60); do
  STATUS=$(aws stepfunctions describe-execution \
    --execution-arn "$RETRY_ARN" \
    --query status \
    --output text)
  if test "$STATUS" != RUNNING; then break; fi
  sleep 2
done
aws stepfunctions describe-execution \
  --execution-arn "$RETRY_ARN" \
  --query '{Status:status,Output:output}'
aws stepfunctions get-execution-history \
  --execution-arn "$RETRY_ARN" \
  --query 'events[?type==`TaskFailed` || type==`TaskSucceeded`].{Type:type,Error:taskFailedEventDetails.error}'
aws dynamodb get-item \
  --table-name labex-ev04-orders \
  --key '{"id":{"S":"retry-order"}}' \
  --query Item
aws dynamodb get-item \
  --table-name labex-ev04-attempts \
  --key '{"id":{"S":"retry-order"}}' \
  --query Item

最終状態は SUCCEEDED で、完了したサマリーは 2/600 です。履歴には、TransientOrderError の TaskFailed が 1 件あり、その後に保存成功とサマリー読み取りの 2 件の TaskSucceeded イベントがあります。ネイティブな注文は数量 2、合計 600 で、診断用試行回数は 2 です。再試行と業務書き込みの回数は異なります。

次に、ワーカーの永続的な失敗モードを使います。

PERMANENT_ARN=$(aws stepfunctions start-execution \
  --state-machine-arn "$MACHINE_ARN" \
  --name permanent-order \
  --input '{"id":"permanent-order","quantity":2,"mode":"permanent"}' \
  --query executionArn \
  --output text)
for attempt in $(seq 1 30); do
  STATUS=$(aws stepfunctions describe-execution \
    --execution-arn "$PERMANENT_ARN" \
    --query status \
    --output text)
  if test "$STATUS" != RUNNING; then break; fi
  sleep 2
done
aws stepfunctions describe-execution \
  --execution-arn "$PERMANENT_ARN" \
  --query '{Status:status,Error:error}'
aws stepfunctions get-execution-history \
  --execution-arn "$PERMANENT_ARN" \
  --query 'events[?type==`TaskFailed` || type==`FailStateEntered`].{Type:type,Error:taskFailedEventDetails.error,State:stateEnteredEventDetails.name}'
aws dynamodb get-item \
  --table-name labex-ev04-orders \
  --key '{"id":{"S":"permanent-order"}}' \
  --query Item

1 回の実際のワーカー呼び出しが InvalidOrder で失敗します。Catch は Rejected に進み、実行は OrderRejected を伴う FAILED で終了します。一時的な失敗の再試行は、この永続的なエラーに一致しません。permanent-order の業務アイテムはありません。

最後に、ワークフローの呼び出し権限付与だけを削除します。操作担当者は実行を開始できますが、ワークフローロールはワーカーを呼び出せません。

aws iam delete-role-policy --role-name labex-ev04-workflow-role --policy-name InvokeWorker
DENIED_ARN=$(aws stepfunctions start-execution \
  --state-machine-arn "$MACHINE_ARN" \
  --name denied-order \
  --input '{"id":"denied-order","quantity":2,"mode":"flaky"}' \
  --query executionArn \
  --output text)
for attempt in $(seq 1 30); do
  STATUS=$(aws stepfunctions describe-execution \
    --execution-arn "$DENIED_ARN" \
    --query status \
    --output text)
  if test "$STATUS" != RUNNING; then break; fi
  sleep 2
done
aws stepfunctions describe-execution \
  --execution-arn "$DENIED_ARN" \
  --query '{Status:status,Error:error}'
aws dynamodb get-item \
  --table-name labex-ev04-orders \
  --key '{"id":{"S":"denied-order"}}' \
  --query Item
aws iam put-role-policy \
  --role-name labex-ev04-workflow-role \
  --policy-name InvokeWorker \
  --policy-document file://workflow-invoke.json

このアクセス拒否の実行は、ワーカーを呼び出さず、診断データも業務データも作成せずに失敗します。指定したアプリケーションエラーの再試行では、認可の不足を修復できません。意図する権限付与は復元されます。AWS View には、成功した再試行のサマリーと 2 つの失敗が、1 件の注文の隣に表示されます。

以下の例は、実際の再試行のサマリー、永続的な失敗、拒否された実行を、保存された注文とともに示します。

AWS View に実際の再試行成功と永続的な失敗が表示される

実際の復旧の検証を実行してください。

ワークフローリソースと合成結果を削除する

このステップでは、提供された準備リソースを保持しながら、自分の完了したステートマシン、ワークフローロール、注文、ログを削除します。

3 つの実行はすべて終了しています。ステートマシンの削除は、アクティブなステートマシン一覧からそれを取り除きます。ロールを削除する前に所有するロールポリシーを削除し、その後、合成注文と実行によって作成されたワーカーロググループを削除します。

aws stepfunctions delete-state-machine --state-machine-arn "$MACHINE_ARN"
aws iam delete-role-policy --role-name labex-ev04-workflow-role --policy-name InvokeWorker
aws iam delete-role --role-name labex-ev04-workflow-role
aws dynamodb delete-item --table-name labex-ev04-orders --key '{"id":{"S":"retry-order"}}'
aws dynamodb delete-item \
  --table-name labex-ev04-attempts \
  --key '{"id":{"S":"retry-order"}}'
aws logs delete-log-group --log-group-name /aws/lambda/labex-ev04-worker

成功する一覧取得で、残るものを証明します。

aws stepfunctions list-state-machines
aws iam list-roles --query 'Roles[].RoleName'
aws dynamodb scan --table-name labex-ev04-orders --query Items
aws logs describe-log-groups --query logGroups
aws dynamodb scan --table-name labex-ev04-reference --query Items

アクティブなステートマシン、注文、ロググループはありません。提供されたワーカーロールだけが残り、参照アイテムは変わりません。提供されたワーカーとテーブルは保持してください。準備時の所有範囲は、自分が作成したワークフローやリソースと異なります。ネットワークエラーや認証エラーは削除の証拠になりません。

このラボで作成した通常のファイルを削除します。

rm -f workflow-trust.json workflow-invoke.json workflow-template.json workflow.json

AWS View には、空のステートマシン・実行・注文と、保持された参照リソースが表示されます。VM を終了する前に、後片付けの検証を実行してください。

まとめ

特定の一時的な失敗に対して回数を限定した再試行を設定し、Catch で明示的な永続的失敗へ進むようにしました。ネイティブな履歴と実際の注文で、試行と業務書き込みを区別しました。権限拒否では、ワーカー実行も業務上の効果も発生しませんでした。提供された準備リソースを保持しながら、所有するワークフローリソースと結果を削除しました。

次のユニットでは、再試行すると効果が繰り返される可能性のある、業務書き込み後の失敗を扱います。