AWS Step Functionsの変数とJSONataで一定回数のループを実現する
データ事業本部の鈴木です。
テストなどでAWSのサービスに対して同じ処理の繰り返しを行いたいことがあり、AWS Step Functionsを使った実装を試したいなと考えていたのですが、少し前に変数とJSONataのサポートがされたお知らせがあったのを思い出したので、この機能を使った実装を検証しました。
ステートマシンで一定回数のループを実現するには
ステートマシンで一定回数のループを実現するのは、実はこれまでは工夫が必要でした。同期実行をサポートしていないAPIを利用する場合などでは、例えば以下の記事のように、ステートマシン内でAPI呼び出しを行った後、APIで実行した機能の終了ステータスを別途取得し、その値を見てループを抜けるというような実装が一般的です。
一方で、一定回数でループを抜けるためには、例えば以下のガイドのようにLambdaでインクリメントを行っていくというような、擬似的に先のループの仕組みを作るような工夫が必要でした。
そのほかには加算でLambdaを使わないように以下のような工夫をしたりもしていました。
先日のアップデートでStep Functionsが変数とJSONataをサポートしたことにより、変数に値を保持することに加え、その変数をステートマシン内でインクリメントすることができるようになりました。これにより様々な実装がStep Functionsのみで完結するようになりましたが、今回もその機能を利用しています。
変数とJSONataについては以下の資料を見て頂くと分かりやすいです。
- 変数と JSONata を使った AWS Step Functions での開発者エクスペリエンスの簡素化 | Amazon Web Services ブログ
- 「これでLambdaが不要に?!Step FunctionsのJSONata対応について」というタイトルでCM re:Growth 2024 OSAKAに登壇しました #regrowth_osaka | DevelopersIO
実装例の紹介
全体像とコード
Step Functions Workflow Studioで以下のステートマシンを作成しました。QueryLanguage
として新しく利用できるようになったJSONataを使っています。loop_cnt
変数をループ内でインクリメントして、30を超えるとループを抜けて終了します。
{
"QueryLanguage": "JSONata",
"Comment": "A description of my state machine",
"StartAt": "Init",
"States": {
"Init": {
"Type": "Pass",
"Assign": {
"loop_cnt": 0
},
"Next": "Add"
},
"Add": {
"Type": "Pass",
"Assign": {
"loop_cnt": "{% $loop_cnt + 1 %}"
},
"Next": "Choice"
},
"Choice": {
"Type": "Choice",
"Choices": [
{
"Next": "Add",
"Condition": "{% $loop_cnt <= 29 %}"
}
],
"Default": "Pass"
},
"Pass": {
"Type": "Pass",
"End": true,
"Output": {
"loop_cnt": "{% $loop_cnt %}"
}
}
}
}
ループを抜ける判定は今回はChoiceに不等式でハードコードしていますが、ここも変数やパラメータにするとより汎用性が広がりそうです。(無限ループにだけ気をつけましょう!)
上記だけだとただループするだけのステートマシンになるので、別途ループ内にサービスを利用するためのステートを追加するイメージです。
実行例
Initステートでloop_cnt
変数を初期化し、ループを開始します。
最終的にloop_cnt
は30になって終了しました。
ポイント
変数初期値の設定
初期値はpassステートで設定しました。
"Init": {
"Type": "Pass",
"Assign": {
"loop_cnt": 0
},
"Next": "Add"
},
変数のインクリメント
JSONataを使うことで、変数に対して値の更新ができるため、インクリメントするようにしました。
"Add": {
"Type": "Pass",
"Assign": {
"loop_cnt": "{% $loop_cnt + 1 %}"
},
"Next": "Choice"
},
Choiceでの変数評価
こちらもJSONataを使っています。
以下のガイドから、変数x
の参照は$x
というように行えることが読み取れたので、Choiceのルールで評価しました。
"Choice": {
"Type": "Choice",
"Choices": [
{
"Next": "Add",
"Condition": "{% $loop_cnt <= 29 %}"
}
],
"Default": "Pass"
},
最後に
変数とJSONataを使うことで、Step Functionsだけで非常に簡単に一定回数のループを実現できました。
参考になりましたら幸いです。