Step Functionsのパラメータをうまく使いこなそう
- Lipton
- 4 時間前
- 読了時間: 8分
目次
Step Functions とは?
パラメータ とは?
パラメータの例
パラメータをうまく活用するには
最後に
AWS Step Functionsとは?
AWS Step Functionsは、状態遷移を定義するステートマシン型のオーケストレーションサービスです。複数のAWSサービス(Lambda、SQS、DynamoDBなど)を組み合わせて、一連の処理フローを設計・実行できます。簡単に言えば、JOBフローを定義できるサービスです。
特徴的な機能として、以下の機能が挙げられます。
ワークフローの可視化
エラーハンドリング、リトライ、分岐、並列処理
サーバーレスとの親和性が高い
JSON形式でワークフロー(ASL: Amazon States Language)を定義
これにより、アプリケーションの制御構造をインフラ側で実装することで、コードの簡素化と可読性の向上が可能になります。

Step Functionsにおける「パラメータ」とは?
Step Functionsの「パラメータ」は、各ステート(状態)に渡す入力値の構造を制御する仕組みです。例えば、Lambda関数に渡すJSONの一部を選んだり、書き換えたりする際に使われます。
ステートが実行されるとき、以下のような入力・出力の仕組みが連続して作用します。
InputPath:元の入力から必要な部分だけを抽出
Parameters:必要な入力値を構造的に再構成
ResultSelector:処理後の結果を整形
OutputPath:出力から必要な部分だけを選択
このうち、Parametersは非常に重要で、外部API呼び出しやLambda関数などへの入力を
自在に作り変えることが可能です。
Parametersは各ステートの実行の際の引数の役割を果たし、そのパラメータを自由に定義することが可能ですが、複雑なJOBフローを定義するステートマシンや大量のJOBを繋ぐステートマシンでは、以下のような問題がしばしば発生します。
パラメータの数が多すぎて可読性が低い
どこに何のパラメータを使用しているのかわからないので、手を入れづらい
このような問題に対処するにあたって、どう対処していったら良いのかを説明します。
パラメータの例
上記で紹介したような、パラメータの数が多い例を以下に挙げます。
{
"param1": "1",
"param2": "2",
"param3": "3",
"param4": "4",
"parameters1": {
"param5": "5",
"param6": "6",
"param7": "7",
"param8": "8",
"param9": "9",
"param10": "10",
"param11": "11",
"param12": "12",
"param13": "13",
"param14": "14",
"param15": "15",
"param16": "16",
"param17": "17",
"param18": "18",
"param19": "19",
"param20": "20",
"param21": "21",
"param22": "22",
"param23": "23",
"parameters1-1": {
"param24": 24,
"param25": 25,
"param26": 26,
"param27": 27,
"param28": 28,
"param29": 29,
"param30": 30,
"param31": 31,
"param32": 32,
"param33": 33,
"param34": "34"
},
"parameters1-2": {
"param35": 35,
"param36": 36,
"param37": 37,
"param38": 38,
"param39": 39,
"param40": 40,
"param41": 41,
"param42": 42,
"param43": 43,
"param44": 44,
"param45": "45"
}
},
"parameters2": {
"param46": "46",
"param47": "47",
"param48": "48",
"param49": "49",
"parameters2-1": {
"param50": "50",
"param51": "51",
"param52": "52",
"param53": "53",
"param54": "54",
"param55": "55",
"param56": "56",
"param57": "57",
"param58": "58",
"param59": "59",
"param60": "60"
},
"parameters2-2": {
"param61": "61",
"param62": "62",
"param63": "63",
"param64": "64",
"param65": "65",
"param66": "66",
"param67": "67",
"param68": "68",
"param69": "69",
"param70": "70"
}
}
}
見てわかる通り、パラメータの数が多くて非常にわかりにくいです。
parameters1というリストの中にさらにparameters1-1やparameters1-2というリストが入れ子になっていますし、似たようなパラメータが冗長的に格納されていそうなこともわかります。
パラメータをうまく活用するには
Step Functions のパラメータをうまく制御するには、以下の3点を活用すると良いと思います。
Passステートでパラメータの再構成を行う
ResultSelectorで必要なパラメータだけに絞って出力、整形する
場合によっては、パラメータをリセットして再構成する
Passステートでパラメータの再構成を行う
Step Functions において定義できるステートの種類の一つに "Pass" があります。
読んで字の如くステートのステータスを成功にして後続のステートに渡す役割ですが、
パラメータの再構成を行うにあたってとても有用な機能です。
以下のようにステートを定義すると、後続のstate1で使用したいパラメータだけを定義することができます。
"ReplaceParameter": {
"Type": "Pass",
"Comment": "InitParameter",
"Parameters": {
"param100.$": "$.param1",
"param200.$": "$.param2",
"param300.$": "$.param3",
"param400.$": "$.parameters1.param13",
"param500.$": "$.parameters1.parameters1-1",
"param600": "600"
},
"ResultPath": "$.forstate1",
"Next": "state1"
},
この場合だと、state1で渡されるパラメータは以下のようになります。
{
〜中略〜
"param1": "1",
"param2": "2",
"param3": "3",
"param4": "4",
"parameters1": {
"param5": "5",
"param6": "6",
"param7": "7",
"param8": "8",
"param9": "9",
"param10": "10",
"param11": "11",
"param12": "12",
"param13": "13",
"param14": "14",
"param15": "15",
"param16": "16",
"param17": "17",
"param18": "18",
"param19": "19",
"param20": "20",
"param21": "21",
"param22": "22",
"param23": "23",
"parameters1-1": {
"param24": 24,
"param25": 25,
"param26": 26,
"param27": 27,
"param28": 28,
"param29": 29,
"param30": 30,
"param31": 31,
"param32": 32,
"param33": 33,
"param34": "34"
},
"parameters1-2": {
"param35": 35,
"param36": 36,
"param37": 37,
"param38": 38,
"param39": 39,
"param40": 40,
"param41": 41,
"param42": 42,
"param43": 43,
"param44": 44,
"param45": "45"
}
},
"parameters2": {
"param46": "46",
"param47": "47",
"param48": "48",
"param49": "49",
"parameters2-1": {
"param50": "50",
"param51": "51",
"param52": "52",
"param53": "53",
"param54": "54",
"param55": "55",
"param56": "56",
"param57": "57",
"param58": "58",
"param59": "59",
"param60": "60"
},
"parameters2-2": {
"param61": "61",
"param62": "62",
"param63": "63",
"param64": "64",
"param65": "65",
"param66": "66",
"param67": "67",
"param68": "68",
"param69": "69",
"param70": "70"
}
},
"forstate1": {
"param100": 1,
"param200": 2,
"param300": 3,
"param400": 13,
"param500": {
"param24": 24,
"param25": 25,
"param26": 26,
"param27": 27,
"param28": 28,
"param29": 29,
"param30": 30,
"param31": 31,
"param32": 32,
"param33": 33,
"param34": "34"
},
"param600": 600,
}
}
ResultPathで "$.forstate1" を指定したので、forstate1という名前のパラメータのリストが追加されました。
このリストをstate1のステートの定義で以下のように指定すれば、必要なパラメータだけを指定して実行することが可能です。
state1のステートの定義
"state1": {
"Comment": "state1",
"Type": "Task",
"Resource": "arn:aws:states:::states:startExecution.sync:2",
"InputPath": "$",
"Parameters": {
"StateMachineArn": "arn:aws:states:ap-northeast-1:123456789012:stateMachine:state1",
"Name.$": "$$.Execution.Name",
"Input.$": "$.forstate1"
},
"Next": "state2"
}
ResultSelectorで必要なパラメータだけに絞って出力、整形する
Step Functions のパラメータを定義する方法の一つとして、Lambdaを利用することが挙げられます。先ほど紹介したPassステートではパラメータ自体の動的な変更はできないため、LambdaやGlue Jobなどを用いて値を変更し、それをStep Functionsに返却する方法が考えられます。
例えば、以下のようなパラメータを返却するLambdaがあったとします。
{
"param1": 100,
"param2": 200,
"param3": 300,
"param4": 400
}
このパラメータをすべてStep Functionsに返却した場合、パラメータは以下のようになります。
{
〜中略〜
"param1": "1",
"param2": "2",
"param3": "3",
"param4": "4",
"parameters1": {
"param5": "5",
"param6": "6",
"param7": "7",
"param8": "8",
"param9": "9",
"param10": "10",
"param11": "11",
"param12": "12",
"param13": "13",
"param14": "14",
"param15": "15",
"param16": "16",
"param17": "17",
"param18": "18",
"param19": "19",
"param20": "20",
"param21": "21",
"param22": "22",
"param23": "23",
"parameters1-1": {
"param24": 24,
"param25": 25,
"param26": 26,
"param27": 27,
"param28": 28,
"param29": 29,
"param30": 30,
"param31": 31,
"param32": 32,
"param33": 33,
"param34": "34"
},
"parameters1-2": {
"param35": 35,
"param36": 36,
"param37": 37,
"param38": 38,
"param39": 39,
"param40": 40,
"param41": 41,
"param42": 42,
"param43": 43,
"param44": 44,
"param45": "45"
}
},
"parameters2": {
"param46": "46",
"param47": "47",
"param48": "48",
"param49": "49",
"parameters2-1": {
"param50": "50",
"param51": "51",
"param52": "52",
"param53": "53",
"param54": "54",
"param55": "55",
"param56": "56",
"param57": "57",
"param58": "58",
"param59": "59",
"param60": "60"
},
"parameters2-2": {
"param61": "61",
"param62": "62",
"param63": "63",
"param64": "64",
"param65": "65",
"param66": "66",
"param67": "67",
"param68": "68",
"param69": "69",
"param70": "70"
}
},
"Payload": {
"param1": 100,
"param2": 200,
"param3": 300,
"param4": 400
}
}
Lambdaで返却された値は、Step Functions上ではデフォルトでPayLoadというキーの中に格納されます。なので、何も設定をしないと後続のLambdaの出力のPayLoadで上書きされてしまいます。
そこで、出力した値を明示的に定義するために "ResultSelector"と"ResultPath"を使います。以下のように"ResultSelector"と"ResultPath"で定義すると、param1とparam3だけを
Step Functions のパラメータとして利用することができます。
state1のステートの定義
"state1": {
"Comment": "state1",
"Type": "Task",
"Resource": "arn:aws:states:::lambda:invoke",
"InputPath": "$",
"Parameters": {
"FunctionName": "arn:aws:states:ap-northeast-1:123456789012:function:state1",
"Name.$": "$$.Execution.Name",
"Input.$": "$"
},
"ResultSelector": {
"param1.$": "$.Payload.param1",
"param3.$": "$.Payload.param3"
},
"ResultPath": "$.state1",
"OutputPath": "$",
"Next": "state2"
}
上記の定義で実行した場合、実行後に出力されるパラメータは以下のようになります。
{
〜中略〜
"param1": "1",
"param2": "2",
"param3": "3",
"param4": "4",
"parameters1": {
"param5": "5",
"param6": "6",
"param7": "7",
"param8": "8",
"param9": "9",
"param10": "10",
"param11": "11",
"param12": "12",
"param13": "13",
"param14": "14",
"param15": "15",
"param16": "16",
"param17": "17",
"param18": "18",
"param19": "19",
"param20": "20",
"param21": "21",
"param22": "22",
"param23": "23",
"parameters1-1": {
"param24": 24,
"param25": 25,
"param26": 26,
"param27": 27,
"param28": 28,
"param29": 29,
"param30": 30,
"param31": 31,
"param32": 32,
"param33": 33,
"param34": "34"
},
"parameters1-2": {
"param35": 35,
"param36": 36,
"param37": 37,
"param38": 38,
"param39": 39,
"param40": 40,
"param41": 41,
"param42": 42,
"param43": 43,
"param44": 44,
"param45": "45"
}
},
"parameters2": {
"param46": "46",
"param47": "47",
"param48": "48",
"param49": "49",
"parameters2-1": {
"param50": "50",
"param51": "51",
"param52": "52",
"param53": "53",
"param54": "54",
"param55": "55",
"param56": "56",
"param57": "57",
"param58": "58",
"param59": "59",
"param60": "60"
},
"parameters2-2": {
"param61": "61",
"param62": "62",
"param63": "63",
"param64": "64",
"param65": "65",
"param66": "66",
"param67": "67",
"param68": "68",
"param69": "69",
"param70": "70"
}
},
"state1": {
"param1": 100,
"param3": 300
}
}
場合によっては、パラメータをリセットして再構成する
パラメータが増えすぎてしまったり、現在のパラメータのままだと後続のステートの実行に不都合がある場合など、Step Functions のパラメータをリセットして最初から再構成させたいと思うことがあると思います。
パラメータのリセット方法は実に簡単で、"ResultPath" に"$"を指定するだけです。
以下のようなステートの定義でパラメータをリセットすることができます。
state1のステートの定義
"state1": {
"Comment": "state1",
"Type": "Task",
"Resource": "arn:aws:states:::lambda:invoke",
"InputPath": "$",
"Parameters": {
"FunctionName": "arn:aws:states:ap-northeast-1:123456789012:function:state1",
"Name.$": "$$.Execution.Name",
"Input.$": "$"
},
"ResultSelector": {
"param1.$": "$.Payload.param1",
"param3.$": "$.Payload.param3"
},
"ResultPath": "$",
"OutputPath": "$",
"Next": "state2"
}
ResultSelectorで定義したパラメータのみが後続に渡されるので、
上記の定義で実行した場合、後続のステートに渡るパラメータは以下のようになります。
{
"param1": 100,
"param3": 300
}
パラメータのリセットは簡単にできますが、一つ間違えると今までのパラメータを消してしまうことになるので、設定時には十分に注意が必要です。
最後に
AWS Step Functionsにおけるパラメータは複雑で難しいですが、うまく活用できればより複雑な状態制御が可能になります。
今までプログラム上や手動でやるしかなかった分岐処理や実行制御をStep Functionsで実行できるようになったり、ワークフローをStep Functionsに保存することで管理がよりしやすくなるなど、得られる恩恵は多くなると思います。
コメント