kakakakakku blog

Weekly Tech Blog: Keep on Learning!

Step Functions の新機能「変数」と「JSONata」を AWS と LocalStack で試す

2024年11月22日に AWS Step Functions で新機能「変数 (variables)」「JSONata」がサポートされた❗️

aws.amazon.com

特に「変数」は待望の機能なんじゃないかな〜と思う.今までは AWS Step Functions でタスク結果を引き回すときにどうしてもバケツリレーが必要で,正直 ResultSelector / ResultPath という構文も難しく(何度書いても忘れてしまう😇)ある程度複雑なワークフローを実装するときはデータシュミレーターがないと無理に思えるほどだった.個人的には AWS Step Functions は動くようになったら最高に便利だけどイメージ通りに実装するまでの過程が結構大変〜というイメージがある💨

変数と JSONata を試す

さっそく変数と JSONata を試してみる❗️今回は AWS Lambda 関数から出力された数値同士を「掛け算」するサンプルにする.実は今までの AWS Step Functions 組み込み関数では States.MathAdd を使った「足し算」しかサポートされてなく,過去に困った経験があった.

docs.aws.amazon.com

AWS Step Functions ワークフロー

以下のようなワークフローを作った.AWS Lambda 関数 returnXreturnY はランダムな整数を返して結果を「変数」設定し,最後の Pass では「JSONata」を使って returnXreturnY の値を計算(掛け算)する👌

ステートマシンは必要最低限にしていて,ポイントをザッと以下に挙げる📝

  • QueryLanguageJSONata を指定する
  • Assign を使って AWS Lambda 関数 returnXreturnY の結果 {% $states.result.body %} を変数に設定する
  • JSONata 式 {% $x * $y %} で計算(掛け算)する
{
  "QueryLanguage": "JSONata",
  "StartAt": "returnX",
  "States": {
    "returnX": {
      "Type": "Task",
      "Resource": "arn:aws:lambda:ap-northeast-1:000000000000:function:returnX",
      "Assign": {
        "x": "{% $states.result.body %}"
      },
      "Next": "returnY"
    },
    "returnY": {
      "Type": "Task",
      "Resource": "arn:aws:lambda:ap-northeast-1:000000000000:function:returnY",
      "Assign": {
        "y": "{% $states.result.body %}"
      },
      "Next": "multiplication"
    },
    "multiplication": {
      "Type": "Pass",
      "Output": {
        "multiplication": "{% $x * $y %}"
      },
      "End": true
    }
  }
}

AWS Lambda 関数 returnXreturnY の実装はシンプル💡

import json
import random

def lambda_handler(event, context):
    return {
        'statusCode': 200,
        'body': random.randint(1, 100)
    }

ちなみに 0 ≤ n < 1 の範囲でランダムな値を取得するなら JSONata の $random() 関数で表現できてしまう.あくまで今回は AWS Lambda 関数で何かしらの処理を実行するサンプルとして見てもらえればと👌

docs.jsonata.org

実行結果

AWS Step Functions ワークフローを実行すると期待通りに「変数」「JSONata」を使えた❗️

注意点

今回のリリースと同時に今まで何度もお世話になったデータフローシュミレーターがメンテナンスされなくなっていた😇

LocalStack で変数と JSONata を試す

今回さらにスゴイのは LocalStack も同時に変数と JSONata をサポートしている点で,リリースノートにも LocalStack の紹介文が載っていた❗️

We have also partnered with LocalStack and Datadog to ensure that their local emulation and observability experiences are updated to support Variables and JSONata.

そして LocalStack 側のブログにも記事が出ている📝

blog.localstack.cloud

正確には LocalStack v4.0.1 でサポートされているため,今回は最新の LocalStack v4.0.2 で試す.

github.com

AWS Step Functions ワークフロー

以下の AWS SAM テンプレートを準備した.マネジメントコンソールで試した構成とほぼ同じ👌

AWSTemplateFormatVersion: 2010-09-09
Transform: AWS::Serverless-2016-10-31

Resources:
  FunctionReturnX:
    Type: AWS::Serverless::Function
    Properties:
      FunctionName: returnX
      CodeUri: ./src
      Handler: app.lambda_handler
      Runtime: python3.12
      Architectures:
        - x86_64
  FunctionReturnY:
    Type: AWS::Serverless::Function
    Properties:
      FunctionName: returnY
      CodeUri: ./src
      Handler: app.lambda_handler
      Runtime: python3.12
      Architectures:
        - x86_64
  StateMachine:
    Type: AWS::Serverless::StateMachine
    Properties:
      Name: sandbox
      DefinitionUri: ./sandbox.asl.json
      DefinitionSubstitutions:
        FunctionXArn: !GetAtt FunctionReturnX.Arn
        FunctionYArn: !GetAtt FunctionReturnY.Arn

ステートマシン sandbox.asl.json もほぼ同じで,AWS Lambda 関数名の ARN を AWS SAM テンプレートから渡すところが違う👌

{
  "QueryLanguage": "JSONata",
  "StartAt": "returnX",
  "States": {
    "returnX": {
      "Type": "Task",
      "Resource": "${FunctionXArn}",
      "Assign": {
        "x": "{% $states.result.body %}"
      },
      "Next": "returnY"
    },
    "returnY": {
      "Type": "Task",
      "Resource": "${FunctionYArn}",
      "Assign": {
        "y": "{% $states.result.body %}"
      },
      "Next": "multiplication"
    },
    "multiplication": {
      "Type": "Pass",
      "Output": {
        "multiplication": "{% $x * $y %}"
      },
      "End": true
    }
  }
}

次に LocalStack にデプロイすると LocalStack Resource Browser で確認できる❗️

$ samlocal build 
$ samlocal deploy

そして LocalStack 上の AWS Step Functions ワークフローを実行すると,{\"multiplication\":1344} と出力されていて期待通りに計算(掛け算)できている👏

最高だ〜 \( 'ω')/

$ awslocal stepfunctions start-execution --state-machine-arn arn:aws:states:ap-northeast-1:000000000000:stateMachine:sandbox
{
    "executionArn": "arn:aws:states:ap-northeast-1:000000000000:execution:sandbox:ac69989b-6569-4881-aea7-23de22d124ba",
    "startDate": "2024-11-28T00:00:00.000000+09:00"
}

$ awslocal stepfunctions describe-execution --execution-arn arn:aws:states:ap-northeast-1:000000000000:execution:sandbox:ac69989b-6569-4881-aea7-23de22d124ba
{
    "executionArn": "arn:aws:states:ap-northeast-1:000000000000:execution:sandbox:ac69989b-6569-4881-aea7-23de22d124ba",
    "stateMachineArn": "arn:aws:states:ap-northeast-1:000000000000:stateMachine:sandbox",
    "name": "ac69989b-6569-4881-aea7-23de22d124ba",
    "status": "SUCCEEDED",
    "startDate": "2024-11-28T00:00:00.000000+09:00",
    "stopDate": "2024-11-28T00:00:00.000000+09:00",
    "input": "{}",
    "inputDetails": {
        "included": true
    },
    "output": "{\"multiplication\":1344}",
    "outputDetails": {
        "included": true
    }
}

LocalStack Resource Browser でも実行結果を確認できた❗️(今のところ変数は表示されていなさそうだった)

関連記事

aws.amazon.com

関連ドキュメント

docs.jsonata.org

docs.aws.amazon.com