AWS Step Functions と lambda を使用しアプリケーションエラーに対処する(AWSハンズオン)


AWS Lambdaに記述するエラー処理コードの量を減らすために、AWS Step Functions を使用して関数のエラー処理をサポートするサーバーレスワークフローを作成していきます。
Lambdaの言語はPythonです。
ちなみに今回はAWSの公式にある<a href="https://aws.amazon.com/jp/getting-started/hands-on/handle-serverless-application-errors-step-functions-lambda/">ハンズオン</a>を実施したものになります。

# 目次
<ol>
<li>StepFunctionで呼び出すLambdaの作成</li>
<li>Stepfunctionの作成</li>
<li>実行結果</li>
</ol>

<h3 id="1">1.StepFunctionで呼び出すLambdaの作成</h3>

まずはLambdaの作成をクリックしてLambdaを作成していきます。
今回は自前のコードを入力するので「一から作成」をクリックして関数名とランタイムを選択していきます。
私は関数名をハンズオン通り「MockAPIFunction」とします。
ロールについてですが、今回はステップファンクションからのLambdaへの許可があればよいので、
Lambdaのロールの方は適当に作って、特にポリシーもアタッチしなくてよいです。

![スクリーンショット 2023-02-11 222801.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1260979/6f83c15d-f9a7-15a0-cb71-19a5a9170504.png)

Lambdaが作成されたら下記のコードを入力してください。

```
class TooManyRequestsException(Exception): pass
class ServerUnavailableException(Exception): pass
class UnknownException(Exception): pass

def lambda_handler(event, context):
    statuscode = event["statuscode"]    
    if statuscode == "429":
        raise TooManyRequestsException('429 Too Many Requests')
    elif statuscode == "503":
        raise ServerUnavailableException('503 Server Unavailable')
    elif statuscode == "200":
        return '200 OK'
    else:
        raise UnknownException('Unknown error')
```

class 例外クラス: pass
例外を発生させるための例外クラスを作っている。

def lambda_handler(event, context):以下
引数のステータスコードによって、例外とメッセージを発生させる。

raiseコマンドについては下記の動画が分かりやすかったので例外について分からない人はぜひご覧ください。
<a href="https://www.youtube.com/watch?v=qwUaTbdI3O0">【Pythonプログラミング】意図的に例外を発生させる方法 (raise) ！なぜ、そんなことをする必要があるのかを解説します！</a>

これでLambdaの方は完成です。


<h3 id="2">2.Stepfunctionの作成</h3>


Stepfunctionには視覚的に設計ができる画期的な技術がありますが、
今回はコードを入力するので「コードでワークフローを記述」を選択。

![スクリーンショット 2023-02-11 230147.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1260979/d898d78d-f9a8-43ef-c6c9-2f722dc97da6.png)

定義で下記のコードを入力してください。

```
{
  "Comment": "An example of using retry and catch to handle API responses",
  "StartAt": "Call API",
  "States": {
    "Call API": {
      "Type": "Task",
      "Resource": "arn:aws:lambda:REGION:ACCOUNT_ID:function:FUNCTION_NAME",
      "Next" : "OK",
      "Comment": "Catch a 429 (Too many requests) API exception, and resubmit the failed request in a rate-limiting fashion.",
      "Retry" : [ {
        "ErrorEquals": [ "TooManyRequestsException" ],
        "IntervalSeconds": 1,
        "MaxAttempts": 2
      } ],
      "Catch": [ 
        {
          "ErrorEquals": ["TooManyRequestsException"],
          "Next": "Wait and Try Later"
        }, {
          "ErrorEquals": ["ServerUnavailableException"],
          "Next": "Server Unavailable"
        }, {
          "ErrorEquals": ["States.ALL"],
          "Next": "Catch All"
        }
      ]
    },
    "Wait and Try Later": {
      "Type": "Wait",
      "Seconds" : 1,
      "Next" : "Change to 200"
    },
    "Server Unavailable": {
      "Type": "Fail",
      "Error":"ServerUnavailable",
      "Cause": "The server is currently unable to handle the request."
    },
    "Catch All": {
      "Type": "Fail",
      "Cause": "Unknown error!",
      "Error": "An error of unknown type occurred"
    },
    "Change to 200": {
      "Type": "Pass",
      "Result": {"statuscode" :"200"} ,
      "Next": "Call API"
    },
    "OK": {
      "Type": "Pass",
      "Result": "The request has succeeded.",
      "End": true
    }
  }
}

```

タスク「Call API」の下記の部分は作成したLambdaのARNを入力してください。
```
      "Resource": "arn:aws:lambda:REGION:ACCOUNT_ID:function:FUNCTION_NAME",
```
![スクリーンショット 2023-02-11 234429.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1260979/0241d705-365c-3cb8-fcb7-ade4c21f42f5.png)

コードを簡単に説明すると、タスク「Call API」から始まり、
タスク「Call API」で引数によって、エラーがなければ、タスク「OK」へ遷移し、
エラーによって下記に分岐する内容です。
・TooManyRequestsException
・ServerUnavailableException
・States.ALL

```
      "Seconds" : 1,
      "Next" : "Change to 200"
```
「TooManyRequestsException」の場合は、一秒待ってから次に「Change to 200」が指定されています。


```
    "Change to 200": {
      "Type": "Pass",
      "Result": {"statuscode" :"200"} ,
      "Next": "Call API"
```
「Change to 200」はそのままステータスコード200の出力をして、
タスク「Call API」に戻します。

作成後、ワークフローは下記のように表示されます。

![スクリーンショット 2023-02-11 232232.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1260979/885ba88d-f259-a423-f738-75cf316a4350.png)

次にロールとステップファンクションの名前を入力し手作成完了です。
ロールはLambdaにアクセスできるようにしてください。

![スクリーンショット 2023-02-11 233241.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1260979/0ef6f053-9281-69d8-3b7a-6433ec847708.png)

これでステップファンクションも完了です。


<h3 id="3">3.実行結果</a>

では実行していきます。「実行の開始」をクリックします。
![スクリーンショット 2023-02-11 234727.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1260979/74304907-8740-4dcd-3a55-e623e08660bf.png)

引数はステータスコード200を入力します。
![スクリーンショット 2023-02-11 233821.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1260979/2502011a-5793-aa97-1afb-c5d6e7fee394.png)

成功しました。
![スクリーンショット 2023-02-11 234014.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1260979/05a2f5ed-3158-da66-d7d5-be4c89eff5e4.png)

次は引数を503にします。
```
{
    "statuscode": "503"
}
```
![タイトルなし.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1260979/5ef8c5fb-7d94-16b7-459e-ab11be5e8ee7.png)

他の引数も試していきます。
```
{
    "statuscode": "429"
}
```
![タイトルなし.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1260979/2042a649-96cb-0f5a-6f03-44c94f7e58c2.png)

最後に想定外の引数を入力します。
```
{
    "statuscode": "999"
}
```
![タイトルなし.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1260979/8d376e9b-192a-c777-d02d-407cbc59691d.png)

うまくいきましたね。
本記事は以上になります。ご覧いただきありがとうございました。