Part.2のおさらい
Part2では、主に以下のことを行いました。
- Lambdaに固定引数を渡してみる
- Lambdaに外部からの引数を渡してみる
- Lambdaにコンテキストオブジェクトを渡してみる
- Lambdaの戻り値を、別のTaskの引数に渡してみる
今回は、その続きからはじめてみます。
ここから始める方は、
https://github.com/hito-psv/sam-demo-005
のコードをgit clone
してもらっても大丈夫ですし、Part2からやってみてもらっても構いません。
今回のターゲット
- Lambdaでランダムな結果を返す
- 結果に応じて、次に実行するタスクを変える
- リトライ時は、しばらく時間が経ってから再実行する
をターゲットにしてみたいと思います。
Lambda部分については、Part2で作成した「HelloWorld」の関数を少しだけいじって、色々試してみたいと思います。
準備
Lambda関数を修正する
現在のコードに、乱数でいくつかのパターンの文字列を返すようにしてみたいと思います。
import logging
import random
logger = logging.getLogger()
logger.setLevel(logging.INFO)
def lambda_handler(event, context):
logger.info(event)
message_array = [
"hello world",
"retry"
]
message = random.choice(message_array)
logger.info(message)
return {
"statusCode": 200,
"body": {
"message": message,
}
}
これで、結果のメッセージには
- hello_world
- retry
のいずれかの文字列が返されます。
ビルド・デプロイする
この状態で、sam build
、sam deploy --guided
を実行し、Lambda関数をデプロイしましょう。
Lambda関数の戻り値によって振る舞いを変える
ステートマシン定義の修正
まずは、ステートマシンの定義を修正します。
修正内容は後ほど説明しますので、まずは、このように修正してみます。
{
"StartAt": "hello world 1",
"States": {
"hello world 1": {
"Type": "Task",
"Resource": "${HelloWorldFunction}",
"Parameters": {
"p1.$": $.p1,
"p2.$": "$.p2",
"p3": {
"p3-1": 20,
"p3-2": "xyz"
},
"all.$": "$"
},
"ResultPath": "$.hello_world_result",
"OutputPath": "$",
"Next": "check state"
},
"retry lambda": {
"Type": "Task",
"Resource": "${HelloWorldFunction}",
"InputPath": "$",
"ResultPath": "$.hello_world_result",
"OutputPath": "$",
"Next": "check state"
},
"check state": {
"Type" : "Choice",
"Choices": [
{
"Variable": "$.hello_world_result.body.message",
"StringEquals": "hello world",
"Next": "hello world 2"
},
{
"Variable": "$.hello_world_result.body.message",
"StringEquals": "retry",
"Next": "wait state"
}
],
"Default": "fail state"
},
"wait state": {
"Type": "Wait",
"Seconds": 5,
"Next": "retry lambda"
},
"hello world 2": {
"Type": "Task",
"Resource": "${HelloWorldFunction}",
"InputPath": "$",
"End": true
},
"fail state": {
"Type": "Fail",
"Cause": "No Matches!"
}
}
}
- 「hello world 1」は次のステートに「check state」のステートを実行する
- 「check state」は「$.hello_world_result.body.message」の値が「hello world」なら、次のステートに「hello world 2」を実行する
- 「check state」は「$.hello_world_result.body.message」の値が「retry」なら、次のステートに「wait state」を実行する
- 「check state」は「$.hello_world_result.body.message」の値が「hello world」「retry」以外なら、次のステートに「fail state」を実行する(今回は起こり得ない)
- 「wait state」は、5秒経ったら「retry lambda」のステートを実行する
- 「retry lambda」は、lambda関数をコールした後、「check state」のステートを実行する
- 「hello world 2」はlambda関数をコールした後、ステート実行を終了する
- 「fail state」は、異常終了としてステート実行を終了する
という記述になっています。
「Choices」の中で
-
Variable
:チェック対象 -
StringEquals
:文字列がこの値と同じなら -
Next
:次に実行するステート
を指定します。
なお、StringEquals
の箇所に指定できる演算は、AWS Step Functions開発者ガイドを参照ください。
ビルド・デプロイする
この状態で、sam build
、sam deploy --guided
を実行し、デプロイしましょう。
ステートマシンの確認
まずは、ステートマシンの定義更新によって、可視化されたステートマシンがどのようになっているかをみてみましょう。
変更したように、「check state」から分岐し、「retry lambda」の後「check state」に戻っていることが確認できたと思います。
ステートマシンを実行してみる
マネジメントコンソールから、ステートマシンを実行してみましょう。
Part.2からの修正のため、入力値のp1、p2を使用するため、入力蘭を以下のように指定してください。
- p1に、9999数値を指定
- p2に「p2 strings.」という文字列を指定
結果をみてみる
まずは、ビジュアルフローを確認してみましょう。
見事に、全パスが通ってくれてます(ランダムなので、「hello world 1」→「check state」→「hello world 2」という流れもありえます)。
では、Choice
の処理が正しく動作しているのか、確認してみましょう。
まずは、「hello world 1」のステートから呼び出されたLambda関数の戻りがこちらです。
bodyのmessage部が「retry」であることが確認できます。
その結果、次に「wait state」が実行され、5秒後(#10と#11の時間をチェック)「retry lambdaのステートが実行されています。
実は、この後、更に2回連続して「retry」が返ってきますが、3回目に「hello world」が返されます。
その後は「hello world 2」のステートが実行されていることがわかります。
そして、そのままステートが終了します。
新しく追加された「Choice」ステート
2020/8/13に、アップデートされた内容があります。
値のテスト(型チェック)
- IsNull
- IsString
- IsNumeric
- IsBoolean
- IsTimestamp
によって、Variable
の型をChoice
で確認することができます。
"Variable": "$.foo",
"IsNull|IsString|IsNumeric|IsBoolean|IsTimestamp": true|false
存在チェック
- IsPresent
によって、Variable
そのものの存在チェックを行うことができます。
"Variable": "$.foo",
"IsPresent": true|false
ワイルドカードチェック
- StringMatches
によって、ワイルドカードを使用した判定チェックが行えます。
"Variable": "$.foo",
"StringMatches": "log-*.txt"
別の入力フィールドとの比較
- StringEqualsPath
によって、入力フィールドを別の入力フィールドと比較できます。状態の変更などを確認するときに使用できます。
"Variable": "$.foo",
"StringEqualsPath": "$.bar"
詳細
こちらから確認できます。
まとめ
今回はChoice
による分岐を行なってみましたが、ここまで来ると、ようやくワークフローっぽくなってきた感じがしますね。
ここまでのPart.1〜Part.3の内容だけでも、ある程度のステートマシンが定義できるようになっているかと思います。
次回は、Lambda以外のサービスをタスク定義で呼び出してみたいと思います。
サンプルコードリポジトリ