AWS Step Functions でランダムな待機時間を実装してみた。JSONata と JSONPath

AWS Step Functions でランダムな待機時間を実装してみた。JSONata と JSONPath

Clock Icon2025.03.12

はじめに

クラウド事業本部の梶原@福岡です。
今回は、AWS Step Functions で動的な待機時間を実装する方法について、JSONata と JSONPath の両方のアプローチをご紹介します。
テスト環境でのシミュレーションや、API呼び出しの間隔をランダム化させたい場合などに有用かと思います。

動的な待機時間が必要なケース

Step Functions のワークフローでは、特定の時間だけ処理を一時停止したい場合があります。

  • API レート制限を回避するための待機時間
  • テスト環境での実際の運用シナリオのシミュレーション

通常、Wait ステートでは固定の秒数や終了時刻を指定しますが、JSONata や JSONPath でランダム関数を使うことで動的に値を計算し、指定できます。

アプローチ1:JSONata を使用したランダム秒待機

JSONata は JSON データに対するクエリおよび変換言語です。
AWS Step Functions で JSONata のサポートが追加され、ステートマシン定義内で複雑な計算や変換が可能になりました。
最初はとっつきにくかったですが、JSONata最高です。

詳細は以下の公式ブログをご参照ください:
Simplifying developer experience with variables and JSONata in AWS Step Functions

ステートマシン定義(JSONata版)

{
  "Comment": "A state machine with random wait time using JSONata",
  "QueryLanguage": "JSONata",
  "StartAt": "CalculateWaitSeconds",
  "States": {
    "CalculateWaitSeconds": {
      "Type": "Pass",
      "Next": "Wait",
      "Assign": {
        "waitSeconds": "{% ($random() * 60 + 1) ~> $floor() %}"
      }
    },
    "Wait": {
      "End": true,
      "Seconds": "{% $waitSeconds %}",
      "Type": "Wait"
    }
  }
}

JSONata版の解説

  • "QueryLanguage": "JSONata" - ステートマシン全体で JSONata を使用することを宣言
  • "waitSeconds": "{% ($random() * 60 + 1) ~> $floor() %}" - ランダムな待機秒数を計算
  • "Seconds": "{% $waitSeconds %}" - 計算した値を使用して待機

JSONataの$random()関数の詳細は公式ドキュメントをご参照ください。

AWSコンソール

step-functions-random-wait-jsonata-jsonpath-1

step-functions-random-wait-jsonata-jsonpath-2

アプローチ2:JSONPath を使用したランダム秒待機

JSONPath は従来から Step Functions でサポートされている式言語です。組み込み関数 States.MathRandom() を使用して、ランダムな値を生成できます。
なお、JSONataが使えるようになったタイミングで、JSONPathでも変数が使えるようになっています。

ステートマシン定義(JSONPath版)

{
  "Comment": "A state machine with random wait time using JSONPath",
  "QueryLanguage": "JSONPath",
  "StartAt": "CalculateWaitSeconds",
  "States": {
    "CalculateWaitSeconds": {
      "Type": "Pass",
      "Assign": {
        "waitSeconds.$": "States.MathRandom(1, 60)"
      },
      "Next": "Wait"
    },
    "Wait": {
      "Type": "Wait",
      "End": true,
      "SecondsPath": "$waitSeconds"
    }
  }
}

JSONPath版の解説

  • "QueryLanguage": "JSONPath" - ステートマシン全体で JSONPath を使用することを宣言
  • "waitSeconds.$": "States.MathRandom(1, 60)" - 1〜60の範囲でランダムな整数を生成
  • "SecondsPath": "$waitSeconds" - 計算した値を使用して待機

States.MathRandom()関数の詳細はAWS公式ドキュメントをご参照ください。

ポイント: 通常秒数を指定するSecondsではなく、SecondsPathを使用します

AWSコンソール

step-functions-random-wait-jsonata-jsonpath-3

step-functions-random-wait-jsonata-jsonpath-4

実行結果

どちらのステートマシンも実行すると、以下のような流れになります:

  1. CalculateWaitSeconds ステートで、ランダムな待機秒数を計算し、waitSeconds 変数に代入
  2. Wait ステートで、計算された秒数(waitSeconds)だけ待機
  3. 実行が完了

AWS Management Console の Step Functions 実行履歴では、各ステートの入出力を確認できます。

step-functions-random-wait-jsonata-jsonpath-6

step-functions-random-wait-jsonata-jsonpath-7

実行時間もランダムな実行時間となっています。

step-functions-random-wait-jsonata-jsonpath-5

まとめ

Step Functions では、JSONata と JSONPath の両方を使って動的な待機時間を実装できます。

なお、Step Functions の Wait ステートは、実は内部的には「アクティブに待機」しているわけではなく、指定された時間が経過したときに再開するようにスケジュールされます。Standard ワークフローの場合、課金もされませんので
待機したいときの相性が良いです。(Expressの場合は待機時間も課金されますのでご注意ください)

以下のCloudFormationテンプレートを使えば、これらの機能を簡単にご自分の環境にデプロイできますので、試してみてください。

CloudFormation テンプレート(JSONata版)

AWSTemplateFormatVersion: '2010-09-09'
Description: 'CloudFormation template for Step Functions with random wait using JSONata'

Resources:
  RandomWaitStateMachineRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Version: '2012-10-17'
        Statement:
          - Effect: Allow
            Principal:
              Service: states.amazonaws.com
            Action: 'sts:AssumeRole'
      ManagedPolicyArns:
        - 'arn:aws:iam::aws:policy/AWSXrayWriteOnlyAccess'

  RandomWaitStateMachine:
    Type: AWS::StepFunctions::StateMachine
    Properties:
      StateMachineName: RandomWaitStateMachine-JSONata
      RoleArn: !GetAtt RandomWaitStateMachineRole.Arn
      Definition:
        Comment: A state machine with random wait time using JSONata
        QueryLanguage: JSONata
        StartAt: CalculateWaitSeconds
        States:
          CalculateWaitSeconds:
            Type: Pass
            Next: Wait
            Assign:
              waitSeconds: "{% ($random() * 60 + 1) ~> $floor() %}"
          Wait:
            End: true
            Seconds: "{% $waitSeconds %}"
            Type: Wait
      StateMachineType: STANDARD

Outputs:
  StateMachineArn:
    Description: ARN of the Random Wait State Machine (JSONata)
    Value: !Ref RandomWaitStateMachine

CloudFormation テンプレート(JSONPath版)

AWSTemplateFormatVersion: '2010-09-09'
Description: 'CloudFormation template for Step Functions with random wait using JSONPath'

Resources:
  RandomWaitStateMachineRoleJSONPath:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Version: '2012-10-17'
        Statement:
          - Effect: Allow
            Principal:
              Service: states.amazonaws.com
            Action: 'sts:AssumeRole'
      ManagedPolicyArns:
        - 'arn:aws:iam::aws:policy/AWSXrayWriteOnlyAccess'

  RandomWaitStateMachineJSONPath:
    Type: AWS::StepFunctions::StateMachine
    Properties:
      StateMachineName: RandomWaitStateMachine-JSONPath
      RoleArn: !GetAtt RandomWaitStateMachineRoleJSONPath.Arn
      Definition:
        Comment: A state machine with random wait time using JSONPath
        StartAt: CalculateWaitSeconds
        States:
          CalculateWaitSeconds:
            Type: Pass
            Assign:
              waitSeconds.$: States.MathRandom(1, 60)
            Next: Wait
          Wait:
            Type: Wait
            End: true
            SecondsPath: $waitSeconds
        QueryLanguage: JSONPath
      StateMachineType: STANDARD

Outputs:
  StateMachineArnJSONPath:
    Description: ARN of the Random Wait State Machine (JSONPath)
    Value: !Ref RandomWaitStateMachineJSONPath

Share this article

facebook logohatena logotwitter logo

© Classmethod, Inc. All rights reserved.