Step FunctionsのChoiceを使用した条件分岐

Step Functions Choice Stateを使用した条件分岐

Step FunctionsのChoiceを使用した条件分岐

AWS DVAの出題範囲であるリファクタリングに関する内容です。

以下のページで、Step Functionsの基本的な事項について取り上げました。

https://awstut.com/2022/06/18/introduction-to-step-functions-with-cfn

上記のページでは、2つのステートで構成されたシンプルなステートマシンを構築しました。
今回は選択ステートを使用して、条件に応じて処理が分岐するステートマシンを構築することを目指します。

構築する環境

Diagram of Step Functions - Conditional branching using Choice State

Step Functionsステートマシン内に、3つのステートを定義します。

各ステートは、以下のLambda関数を実行するタスクとします。

  • Lambda関数1:現在日時情報からUNIX時間を計算し、これが偶数か奇数か判定する。
  • Lambda関数2:偶数であること旨の文字列を返す。
  • Lambda関数3:奇数であること旨の文字列を返す。

関数のランタイム環境はPython3.8とします。

最初のステートが完了後、選択ステートで次に実行するステートを分岐させます。
分岐の条件は、偶数/奇数の判定結果に応じて行います。
この値が偶数の判定だった場合は、Lambda関数2のステートが選ばれ、奇数の判定だった場合は、Lambda関数3のステートが選ばれます。

CloudFormationテンプレートファイル

上記の構成をCloudFormationで構築します。
以下のURLにCloudFormationテンプレートを配置しています。

https://github.com/awstut-an-r/awstut-dva/tree/main/04/003

テンプレートファイルのポイント解説

Lambda関数

関数1

Resources:
  Function1:
    Type: AWS::Lambda::Function
    Properties:
      Code:
        ZipFile: |
          import datetime
          import time

          def lambda_handler(event, context):
            now = datetime.datetime.now()
            epoch_time = int(time.mktime(now.timetuple()))

            return {
              'now':  now.strftime('%Y%m%d%H%M%S%f'),
              'epoch_time': {
                'value': epoch_time,
                'is_even': (not bool(epoch_time % 2))
              }
            }
      FunctionName: !Sub "${Prefix}-function-01"
      Handler: !Ref Handler
      Runtime: !Ref Runtime
      Role: !GetAtt FunctionRole.Arn
Code language: YAML (yaml)

Step Functionsで実行する上で、特別な設定は不要です。

実行するコードに注目します。

現在日時を取得し、これをUNIX時間に変換します。
このUNIX時間の数値を2で割った時の余りを求め、これから偶数/奇数を判定します。

return文で辞書型オブジェクトを返します。
例えば以下のようなオブジェクトとなります。

{
  "now": "20221117135316055513",
  "epoch_time": {
    "value": 1668693196,
    "is_even": True
  }
}
Code language: JSON / JSON with Comments (json)

関数2

Lambdaそのものは関数1と同様です。
実行するコードに注目します。

import datetime
import time

def lambda_handler(event, context):
  return '{epoch_time} is even !'.format(
    epoch_time=event['epoch_time']['value'])
Code language: YAML (yaml)

偶数である旨の文字列を返します。

文字列を作成するために、eventオブジェクトを参照します。
このeventは、関数1で生成される辞書型オブジェクトと同様の構造を持っているものとします。

関数3

import datetime
import time

def lambda_handler(event, context):
  return '{epoch_time} is even !'.format(
    epoch_time=event['epoch_time']['value'])
Code language: YAML (yaml)

こちらも実行するコードに注目します。

内容は関数2とほとんど同様です。
eventオブジェクトを参照し、奇数である旨の文字列を返します。

Step Functions

Resources:
  StateMachine:
    Type: AWS::StepFunctions::StateMachine
    Properties:
      Definition:
        Comment: !Sub "${Prefix}-StateMachine"
        StartAt: FirstState
        States:
          FirstState:
            Type: Task
            Resource: !Ref FunctionArn1
            Next: ChoiceState
          ChoiceState:
            Type: Choice
            Choices:
              - Variable: $.epoch_time.is_even
                BooleanEquals: true
                Next: EvenState
              - Variable: $.epoch_time.is_even
                BooleanEquals: false
                Next: OddState
          EvenState:
            Type: Task
            Resource: !Ref FunctionArn2
            End: true
          OddState:
            Type: Task
            Resource: !Ref FunctionArn3
            End: true
      LoggingConfiguration:
        Destinations:
          - CloudWatchLogsLogGroup:
              LogGroupArn: !GetAtt LogGroup.Arn
        IncludeExecutionData: true
        Level: ALL
      RoleArn: !GetAtt StateMachineRole.Arn
      StateMachineName: !Ref Prefix
      StateMachineType: STANDARD
Code language: YAML (yaml)

ステートマシン全体の構造を確認します。

StartAtプロパティを見ると、FirstStateから処理が開始されることがわかります。
FirstStateでは、関数1を実行します。

その後ChoiceStateに移行し、FirstStateから返ってきた値を参照して、条件分岐の判定が行われます。
「$.epoch_time.is_even」のような記法で参照先を指定することができます。
今回は組み込み関数BooleanEqualsを使用して、真理値を判定します。
この値がtrueの場合、EventStateに移行し、falseの場合はOddStateに移行します。

EventState・OddStateでは、それぞれ関数2・関数3を実行します。
各ステートの終了後、ステートマシン全体の処理が完了となります。

環境構築

CloudFormationを使用して、本環境を構築し、実際の挙動を確認します。

CloudFormationスタックを作成し、スタック内のリソースを確認する

CloudFormationスタックを作成します。
スタックの作成および各スタックの確認方法については、以下のページをご確認ください。

https://awstut.com/2021/12/02/cloudformation-nested-stacks

各スタックのリソースを確認した結果、今回作成された主要リソースの情報は以下の通りです。

  • Step Functionsのステートマシン:dva-04-003
  • Lambda関数1:dva-04-003-function-01
  • Lambda関数2:dva-04-003-function-02
  • Lambda関数3:dva-04-003-function-03

AWS Management Consoleからステートマシンの作成状況を確認します。

Detail of Step Function 1.

正常にステートマシンが作成されていることがわかります。
ChoiceStateから分岐し、2つのステートのどちらかに進んだ後に終了する構成です。

動作確認

1回目

準備が整いましたので、ステートマシンの実行を行います。
AWS Management Consoleから実行する場合は、「Start execution」を押下します。

Detail of Step Function 2.

しばらく待機すると、ステートマシンの実行が正常に完了しました。
今回はChoiceStateからEventStateに移行しました。

Eventsの内容を確認します。

Detail of Step Function 3.

FirstStateで現在日時(2022/11/17 13:53:16)を取得し、これをUNIX時間に変換すると「1668693196」となります。
判定の結果、偶数ということで、「is_even」の値はtrueとなりました。

is_evenの値を踏まえて、ChoiceStateで条件分岐の判定が行われ、EvenStateが選択されたことがわかります。
最終的にEvenStateが実行され、「1668693196 is even !」が出力されました。

2回目

もう一度、ステートマシンを実行します。

Detail of Step Function 4.

ステートマシンの実行が正常に完了しました。
今回はChoiceStateからOddtStateに移行しました。

Eventsの内容を確認します。

Detail of Step Function 5.

FirstStateで現在日時(2022/11/17 14:03:33)を取得し、これをUNIX時間に変換すると「1668693813」となります。
判定の結果、奇数ということで、「is_even」の値はfalseとなりました。

is_evenの値を踏まえて、ChoiceStateで条件分岐の判定が行われ、OddStateが選択されたことがわかります。
最終的にOddStateが実行され、「1668693813 is odd !」が出力されました。

まとめ

Step Functionsの選択ステートを使用して、条件に応じて処理が分岐するステートマシンを構築しました。