Step Functionsでパラメータをバリデーションする方法

ステートマシン定義で存在しないパラメータを指定した場合、States.Runtimeエラーが発生し、処理が終了します。このエラーを防ぐために、Choiceステートを使用して、パラメータが存在するかを検証する方法を紹介します。
2022.08.12

こんにちは、ヤギです。

今回の記事は Step Functionsのパラメータをバリデーションする方法です。

Step Functionsは、アクション間でパラメータ指定して、受け渡すことができます。 しかし、存在しないパラメータをASLで指定すると、States.Runtimeエラーが発生します。このエラーはリトライ、キャッチすることができず、ジョブが途中終了します。
また、このStates.RuntimeエラーはStates.ALLでは検出されません。

例えばCatchでエラー通知を行なっていた場合、通知処理が実行されないため、ジョブの失敗に気づくことができません。

このため、存在が保証出来ないパラメータをASLで指定する場合は、事前にパラメータが存在するかどうかのバリデーションが必要です。

TL;DR

  • 存在しないパラメータをASLで指定するとStates.Runtimeが発生する
  • States.Runtimeはキャッチ、リトライが出来ない
  • Choiceステートでパラメータをバリデーションする

前提

入力値$.lambdaInputをLambda関数に渡し、エラーが起きなければ正常終了、エラーが発生すればエラーハンドリングを行う、というシンプルなステートマシンを例に検証します。

{
  "StartAt": "Invoke Lambda Function",
  "States": {
    "Invoke Lambda Function": {
      "Type": "Task",
      "Resource": "arn:aws:states:::lambda:invoke",
      "Parameters": {
        "FunctionName": "arn:aws:lambda:ap-northeast-1:123456789012:function:my-function",
        "Payload.$": "$.lambdaInput"
      },
      "Catch": [
        {
          "ErrorEquals": [
            "States.ALL"
          ],
          "Next": "Notify Job Failure"
        }
      ],
      "End": true
    },
    "Notify Job Failure": {
      "Type": "Fail",
      "Cause": "Job Failed"
    }
  }
}

存在しないパラメータをASLで参照した場合

このASLではLambdaに$.lambdaInputを渡しています。 以下の入力値でステートマシンを実行した場合、$.lambdaInputが存在しないため、States.Runtimeエラーが発生します。

{
    "otherKey": "hogehoge"
}

ステートマシン実行結果

例外内容

エラー
States.Runtime

原因
An error occurred while executing the state 'Invoke Lambda Function' (entered at the event id #2). The JSONPath '$.lambdaInput' specified for the field 'Payload.$' could not be found in the input '{
    "Comment": "Insert your JSON here"
}'

CatchでStates.ALLを指定していますが、States.Runtimeエラーはキャッチされていません。(Notify Job Failureが実行されてない)
公式ドキュメントでも言及されている通り、States.RuntimeStates.ALLではキャッチされません。また、リトライ、キャッチ自体も行うことができません。

States.Runtime エラーは再試行可能ではなく、常に実行が失敗します。States.ALL での再試行またはキャッチでは States.Runtime エラーは検出されません。
https://docs.aws.amazon.com/ja_jp/step-functions/latest/dg/concepts-error-handling.html#states-runtime-error

このため、$.lambdaInputが存在するかを、事前に検証する必要があります。

Choiceステートによるパラメータのバリデーション

$.lambdaInputが存在することを保証するには、パラメータを利用するアクションの前に、Choiceステートを置き、パラメータが存在するかを確認します。

{
  "StartAt": "Validate Params",
  "States": {
    "Validate Params": {
      "Type": "Choice",
      "Choices": [
        {
          "Variable": "$.lambdaInput",
          "IsPresent": false,
          "Next": "Notify Job Failure"
        }
      ],
      "Default": "Invoke Lambda Function"
    },
    "Invoke Lambda Function": {
      "Type": "Task",
      "Resource": "arn:aws:states:::lambda:invoke",
      "Parameters": {
        "FunctionName": "arn:aws:lambda:ap-northeast-1:123456789012:function:my-function",
        "Payload.$": "$.lambdaInput"
      },
      "Catch": [
        {
          "ErrorEquals": [
            "States.ALL"
          ],
          "Next": "Notify Job Failure"
        }
      ],
      "End": true
    },
    "Notify Job Failure": {
      "Type": "Fail",
      "Cause": "Job Failed"
    }
  }
}

これで$.lambdaInputが存在しない場合も、エラーハンドリングが可能になりました。

実際に$.lambdaInputパラメータがない状態で実行してみると、想定通りエラー状態にステートマシンが遷移していることがわかります。  

まとめ

存在しないパラメータをASLで参照するとStates.Runtimeエラーが発生します。このエラーはStates.ALLではキャッチすることができず、ステートマシンの実行失敗に気づけない可能性があります。
存在が保証出来ないパラメータをASLで参照する場合は、Choiceステートで、パラメータが存在するかを確認するようにしましょう。