AWS Step FunctionsとLambdaを使ってじゃんけんのフローを作ってみた

AWS Step FunctionsとLambdaを使ってじゃんけんのフローを作ってみた

Sarah

Sarah

こんにちは。テクニカルディレクターのSarahです。

AWS Step Functionsで分岐処理を行うフローを作ってみたかったので、今回の記事では起動時の入力値とLambdaの関数内で生成した乱数でじゃんけんをさせ、受け取った結果で分岐するワークフローを作成してみました。

事前準備

今回は下記のような流れで行う想定です。

  1. Step Functions起動時に出す手を下記の対応で入力する
    (文字列にしてもよかったですが、直感的にわかりやすいように今回は数字に置き換えています)

    グー 1
    チョキ 2
    パー 3
  2. その値をStep FunctionsからLambdaに渡して、Lambdaで生成した乱数とじゃんけんを行う
  3. Lambdaの結果から勝敗に応じて分岐したタスクに進み、終了

IAMロールの作成

はじめにLambda用のIAMロールを作成します。

IAMとは
認証と許可の仕組み。AWSはセキュリティのベストプラクティスとして最小権限でのアクセス許可を推奨していますが、IAMを使うことでユーザー・グループ・アプリケーションなど用途や実行内容に応じて認証を行うことができます。

IAMロールの作成
ロールを新規作成し、AWSのサービス > Lambdaを選択し、次のステップへ進みます。
 

IAMロールの作成
ポリシーは特に選択せず、ロール名を付けて完了です。

Lambda関数を作成

Lambda関数の作成
「一から作成」を選択、関数名と使用言語を決めて関数を作成します。今回はPythonの3.9にしました。ロールはデフォルトのまま、既存のロールで先ほど作成したロールを指定します。
 

Lambda関数の作成
ソースを書いてデプロイします。

ソースコード

import random

def lambda_handler(event, context):
    rand = random.randint(1, 3) #1から3までの乱数を生成
    if event['InputPath'] == rand:
        result = 'Tied' #入力値とrandが同じならあいこ
    elif event['InputPath'] == 3 and rand == 1:
        result = 'You win' #入力値が3のとき、randが1なら勝ち
    elif event['InputPath'] == 1 and rand == 3:
        result = 'You lose' #入力値が1のとき、randが3なら負け
    elif event['InputPath'] < rand: 
        result = 'You win' #入力値よりもrandが大きければ勝ち
    elif event['InputPath'] > rand:
        result = 'You lose'#入力値よりもrandが小さければ負け
    return {
        "bar":result
    }

(今回初めてPythonを使ったのですが、Pythonのコメントアウトの記号を知らずスラッシュでコメント書こうとしてました。あぶない👦🏻)

ステートマシンの作成

入力値をLambdaに渡し、結果に応じて分岐するフローを作成していきます。

ステートマシンの作成

今回は「コードでワークフローを記述」を選択しました。タイプの種類や引数の書き方など独特なので慣れるまで複雑に感じましたが、JSON形式なのでフォーマット自体はシンプルです。

コードで記述する以外にも、「ワークフローを視覚的に設計」からぽちぽち組み合わせるだけでフローを作成できます。

ソースコード

{
  "Comment": "Tomato",
  "StartAt": "FirstState",
  "States": {
    "FirstState": {
      "Type": "Task",
      "Resource":"作成したLamdaの実行を指定",
      "Parameters":{
        "InputPath.$":"$.throw"
      },
      "Next": "ChoiceState"
    },
    "ChoiceState": {
      "Type":"Choice",
      "Choices": [
        {"Variable":"$.bar",
         "StringEquals":"Tied",
         "Next":"Tied"
        },
        {
          "Variable":"$.bar",
          "StringEquals":"You win",
          "Next":"Won"
        },
        {
          "Variable":"$.bar",
          "StringEquals":"You lose",
          "Next":"Lost"
        }
      ],
      "Default":"DefaultState"
    },
    "Tied":{
      "Type":"Pass",
      "Result":"Tied",
      "Next":"LastState"
    },
    "Won":{
      "Type":"Pass",
      "Result":"Won",
      "Next":"LastState"
    },
    "Lost":{
      "Type":"Pass",
      "Result":"Lost",
      "Next":"LastState"
    },
    "DefaultState":{
      "Type":"Fail",
      "Cause":"Not match"
    },
    "LastState":{
      "Type":"Pass",
      "End":true
    }
  }
}

ステートマシン起動時に入力された値はInputPathで使用することができ、引数+キーで指定できます。

Lambdaの呼び出し方は、呼び出す関数のARNを直接指定する方法と、Lambda:invokeで呼び出す方法の2種類があります。この2つではパラメータの指定の仕方が異なり、後者の場合はParametersの中でARNを指定し、実際の引数はParametersの中のPayloadに指定する形になります。

こちらの記事でこの2つの違いが詳しく解説されていたので、参考にしてみてください。

ステートマシンの作成
こんな感じのフローになりました。

実行

ステートマシンの実行
早速実行してみます。throwというキーで出す手を指定して、ステートマシンを実行します。
 

ステートマシンの実行
無事実行されました。
 

ステートマシンの実行
Lambdaからあいこが出力され、そのままあいこのステートに進んでいるのがわかります。

おわりに

今回はStep Functionsで分岐処理があるフローを作成してみました。

LambdaやAPIゲートウェイと組み合わせたり、コールバック関数を使用して非同期処理にしたりすることで比較的複雑な処理も実現できそうなので、今後も色々試してみたいと思います。

この記事のシェア数

12

Sarah
Sarah テクニカルディレクター / 相川 優子

I define myself as a Japanese-English-programming language interpreter. I’ve come all the way here to make my life good :)