🐋

Step FunctionsのParameterを使って上限ありのループを作る

2024/02/01に公開

概要

Result PathParameterを利用してループのロジックを作成しました。Lambdaで回数を制御するよりも簡易な方法です。

ステートマシン

グラフ

JSON

{
  "Comment": "",
  "StartAt": "Init",
  "States": {
    "Init": {
      "Type": "Pass",
      "Result": [
        true,
        true,
        true,
        false
      ],
      "Next": "Can Execute",
      "ResultPath": "$.canExecute"
    },
    "Can Execute": {
      "Type": "Choice",
      "Choices": [
        {
          "Variable": "$.canExecute[0]",
          "BooleanEquals": true,
          "Comment": "true",
          "Next": "Lambda Invoke"
        }
      ],
      "Default": "Fail"
    },
    "Lambda Invoke": {
      "Type": "Task",
      "Resource": "arn:aws:states:::lambda:invoke",
      "Parameters": {
        "Payload.$": "$",
        "FunctionName": "arn:aws:lambda:ap-northeast-1:876462513854:function:sampleFunc:$LATEST"
      },
      "Retry": [
        {
          "ErrorEquals": [
            "Lambda.ServiceException",
            "Lambda.AWSLambdaException",
            "Lambda.SdkClientException",
            "Lambda.TooManyRequestsException"
          ],
          "IntervalSeconds": 1,
          "MaxAttempts": 3,
          "BackoffRate": 2
        }
      ],
      "Next": "Is Success",
      "ResultPath": "$.output"
    },
    "Is Success": {
      "Type": "Choice",
      "Choices": [
        {
          "Variable": "$.output.Payload.result",
          "BooleanEquals": true,
          "Comment": "true",
          "Next": "Success"
        }
      ],
      "Default": "Pop Element from List"
    },
    "Success": {
      "Type": "Succeed"
    },
    "Pop Element from List": {
      "Type": "Pass",
      "Next": "Wait",
      "Parameters": {
        "canExecute.$": "$.canExecute[1:]"
      }
    },
    "Fail": {
      "Type": "Fail"
    },
    "Wait": {
      "Type": "Wait",
      "Seconds": 5,
      "Next": "Can Execute"
    }
  }
}

やっていること

Init

ループの上限回数を制御するための変数を定義しています。先頭から上限回数分だけtrueを並べた配列を定義します。
後続の処理でもこの変数が使えるように、ResultPathを設定します。

ステートマシン定義(Init部分)
    "Init": {
      "Type": "Pass",
      "Result": [
        true,
        true,
        true,
        false
      ],
      "Next": "Can Execute",
      "ResultPath": "$.canExecute"
    },

Can Execute

canExecuteの先頭の要素がtrueの場合に後続のLambdaを実行するようにします。

ステートマシン定義(Can Execute部分)
    "Can Execute": {
      "Type": "Choice",
      "Choices": [
        {
          "Variable": "$.canExecute[0]",
          "BooleanEquals": true,
          "Comment": "true",
          "Next": "Lambda Invoke"
        }
      ],
      "Default": "Fail"
    },

Invoke Lambda

メイン処理となるLambdaを実行しています。
この例ではサンプルとしてtruefalseを返すだけの関数を実行しています。

Lambda関数
import random

def lambda_handler(event, context):
    return {'result': bool(random.randint(0,1))}
ステートマシン定義(Lambda Invoke部分)
    "Lambda Invoke": {
      "Type": "Task",
      "Resource": "arn:aws:states:::lambda:invoke",
      "Parameters": {
        "Payload.$": "$",
        "FunctionName": "arn:aws:lambda:ap-northeast-1:876462513854:function:sampleFunc:$LATEST"
      },
      "Retry": [
        {
          "ErrorEquals": [
            "Lambda.ServiceException",
            "Lambda.AWSLambdaException",
            "Lambda.SdkClientException",
            "Lambda.TooManyRequestsException"
          ],
          "IntervalSeconds": 1,
          "MaxAttempts": 3,
          "BackoffRate": 2
        }
      ],
      "Next": "Is Success",
      "ResultPath": "$.output"
    },

Is Success

Lambda実行結果を判定しています。trueの場合は処理終了、それ以外の場合はループ(リトライ)処理へ流します。

ステートマシン定義(is Success部分)
    "Is Success": {
      "Type": "Choice",
      "Choices": [
        {
          "Variable": "$.output.Payload.result",
          "BooleanEquals": true,
          "Comment": "true",
          "Next": "Success"
        }
      ],
      "Default": "Pop Element from List"
    },

Pop Element from List

inputとなるcanExecuteの先頭の要素をpopして、新しくoutputとすることでループの回数を制御しています。
下記のようにループが回るごとに先頭から要素がpopされていき、上限回数まで達するとCan Executeステートで実行不可と判定される仕組みです。

  • 1回目: [true, true, true, false][true, true, false]
  • 2回目: [true, true, false][true, false]
  • 3回目: [true, false][false]

これを実現するためにParametersを使用しているのですが、Parametersについては下記を参考にさせていただきました。
https://dev.classmethod.jp/articles/stepfunctions-parameters-inter-states/

また、配列の要素をpopする処理は下記を参考にさせていただきました。
https://docs.aws.amazon.com/ja_jp/step-functions/latest/dg/sample-project-transfer-data-sqs.html#sample-sqs-code-examples

Discussion