Step Functions をざっくり理解する！

## はじめに

実務のシステムアーキテクチャで Step Functions が出てきました🤗
AWS に不慣れな初学者なりに調べた内容をまとめておきます。

## 目次

1. [Step Functionsとは？](#-step-functionsとは)
2. [Step Functionsの具体例](#-step-functionsの具体例)
3. [Step Functionsの構成要素](#-step-functionsの構成要素)
4. [Step Functionsでよく使うステートと実装イメージ](#-step-functionsでよく使うステートと実装イメージ)
5. [Step Functionsのメリット](#-step-functionsのメリット)
6. [ユースケース例](#-ユースケース例)
7. [Step Functionsのエラー処理とリトライの自動化](#-step-functionsのエラー処理とリトライの自動化)
8. [Step Functionsで処理できるエラータイプ](#-step-functionsで処理できるエラータイプ)
9. [エラー・リトライにおけるベストプラクティス](#-エラーリトライにおけるベストプラクティス)
10. [まとめ](#-まとめ)
11. [参考文献](#-参考文献)

## 🧷 Step Functionsとは？
* AWSのサービスの1つ
* 複数の処理を自動でつなぎ合わせて、ワークフローを作成できるサービス

#### 📦 できること…
* 複数の処理を順番に実行したり、並列に実行したりできる
* 処理間の状態管理やエラーハンドリングを自動でやってくれる
* サーバーレスなのでインフラ管理は不要
* Lambda関数やSNS、SQS、DynamoDBなどのAWSサービスと簡単に連携できる

## 🧷 Step Functionsの具体例
### 🛒 ECサイトでの注文処理フロー
例えば、ECサイトで「注文」を受けた時にこんな処理があるとします。

1. 注文データをDBに保存する
2. 決済処理を行う
3. 在庫を確認して引き当てる
4. ユーザーにメールを送信する

これをStep Functionsで自動化すると、以下のような流れになる👇
```yml
　[注文受付] → [決済処理] → [在庫確認] → [メール送信]  
```
* 途中で決済に失敗したらエラーハンドリングを自動実行
* 在庫が不足していたら別の処理に分岐
* すべて成功したら「成功ステータス」を返す

✅ 手動でコードを書くとエラー処理や状態管理が面倒ですが、Step Functionsを使うと上記処理フローが簡単に実装できる！

## 🧷 Step Functionsの構成要素
### ① State Machine (ステートマシン)
ワークフロー全体を定義するもの。
　→ 処理の流れや分岐を記述します。

### ② State (ステート)
ワークフロー内の1つ1つの処理ステップ。
　→ Lambda関数の呼び出しや、条件分岐、待機など。

### ③ 状態遷移
各ステート間の繋がり。
　→ 順次実行・並列実行・条件分岐などを定義。

## 🧷 Step Functionsでよく使うステートと実装イメージ
### ① Taskステート：Lambda関数や別サービスを呼び出す
### ② Choiceステート：条件分岐
### ③ Parallelステート：複数の処理を並列実行
### ④ Waitステート：指定時間待機
### ⑤ Fail/Successステート：エラー終了・成功終了

### ☁️ 実装イメージ
例えば、Lambda関数で「ユーザーの登録 → メール送信 → DB保存」のフローを作る場合👇
```yml
{
  "StartAt": "RegisterUser",
  "States": {
    "RegisterUser": {
      "Type": "Task",
      "Resource": "arn:aws:lambda:us-east-1:123456789012:function:registerUser",
      "Next": "SendEmail"
    },
    "SendEmail": {
      "Type": "Task",
      "Resource": "arn:aws:lambda:us-east-1:123456789012:function:sendEmail",
      "Next": "SaveToDB"
    },
    "SaveToDB": {
      "Type": "Task",
      "Resource": "arn:aws:lambda:us-east-1:123456789012:function:saveToDB",
      "End": true
    }
  }
}
```
これで、ユーザー登録 → メール送信 → DB保存の一連の処理が自動で実行可能！

## 🧷 Step Functionsのメリット
### ✅ 可視化が簡単
* ワークフローの流れがGUIで視覚的に表示されるので、デバッグや修正が楽
### ✅ 自動リトライ & エラーハンドリング
* Lambdaなどが失敗したときに自動で再試行
* 条件に応じてエラーステートに遷移
### ✅ AWSの他サービスと簡単に連携
* Lambda, DynamoDB, SNS, SQSなどとスムーズに連携
### ✅ コスト効率が良い
* ステートマシンの実行回数ごとの課金（1回0.000025ドル）
* サーバーレスなのでインフラ管理不要

## 🧷 ユースケース例
### ① データ処理の自動化
S3にファイルがアップロードされたらStep Functionsで処理フローを実行
### ② バッチ処理の自動化
複数のバッチ処理を順次 or 並列で実行
### ③ ETLパイプライン
DynamoDBにデータを保存 → Athenaでクエリ → 分析処理
### ④ 機械学習ワークフロー
データ取得 → 前処理 → モデル学習 → 推論 → 結果保存

## 🧷 Step Functionsのエラー処理とリトライの自動化
Step Functions でのエラー処理、リトライの自動化の仕組みを以下にて少しメモしておきます。

### ✅ エラー処理 (Error Handling)
* Step Functions では、各ステートでエラーが発生したときにどう対処するかを設定可能
* デフォルトでは、エラーが発生した時点でステートマシンが失敗として終了しますが、 **「リトライ」や「キャッチ」** を設定することで、柔軟なエラー処理が可能になる。

### ⚙️ エラー処理の構成要素
#### ⚠️ リトライ (Retry)
* 処理が失敗した場合に自動で再試行
* 回数や間隔、指数バックオフを指定できる
#### 🚫 キャッチ (Catch)
* エラーが発生したときに別の処理に分岐
* 失敗時に別のステートに遷移してエラーハンドリングを行う

### 🚦 エラー処理の構文例
#### ⚠️ リトライ (Retry) の設定
例えば、Lambda関数が失敗したときに3回まで再試行し、指数バックオフで待機時間を増やす場合👇
```js
{
  "StartAt": "ProcessData",
  "States": {
    "ProcessData": {
      "Type": "Task",
      "Resource": "arn:aws:lambda:us-east-1:123456789012:function:processData",
      "Retry": [
        {
          "ErrorEquals": ["Lambda.ServiceException", "Lambda.AWSLambdaException"],
          "IntervalSeconds": 2,          // 最初の再試行は2秒後
          "MaxAttempts": 3,               // 最大3回まで再試行
          "BackoffRate": 2.0              // 再試行間隔を2倍ずつ増やす
        }
      ],
      "Next": "SuccessState"
    },
    "SuccessState": {
      "Type": "Succeed"
    }
  }
}
```
✅ この場合は以下のように動作します。
* 1回目の失敗 → 2秒後に再試行
* 2回目の失敗 → 4秒後に再試行
* 3回目の失敗 → 8秒後に再試行

それでも失敗した場合はエラー終了

### 🚫 キャッチ (Catch) の設定
Lambda関数が失敗したときに、別の処理に分岐してエラーハンドリングを行う場合👇
```js
{
  "StartAt": "ProcessData",
  "States": {
    "ProcessData": {
      "Type": "Task",
      "Resource": "arn:aws:lambda:us-east-1:123456789012:function:processData",
      "Catch": [
        {
          "ErrorEquals": ["Lambda.ServiceException", "Lambda.AWSLambdaException"],
          "Next": "HandleError"         // エラー時にこのステートへ遷移
        }
      ],
      "Next": "SuccessState"
    },
    "HandleError": {
      "Type": "Task",
      "Resource": "arn:aws:lambda:us-east-1:123456789012:function:sendErrorNotification",
      "Next": "FailState"
    },
    "SuccessState": {
      "Type": "Succeed"
    },
    "FailState": {
      "Type": "Fail"
    }
  }
}
```
✅ この場合は以下のように動作します。
* 成功時 → SuccessState に進む
* 失敗時 → HandleError に遷移してエラーハンドリングを実行

エラーハンドリング後に失敗終了

### 🤖 リトライとキャッチを組み合わせる
リトライしてもダメだった場合にエラーハンドリングに遷移する場合👇
```js
{
  "StartAt": "ProcessData",
  "States": {
    "ProcessData": {
      "Type": "Task",
      "Resource": "arn:aws:lambda:us-east-1:123456789012:function:processData",
      "Retry": [
        {
          "ErrorEquals": ["Lambda.ServiceException"],
          "IntervalSeconds": 3,
          "MaxAttempts": 2,
          "BackoffRate": 2.0
        }
      ],
      "Catch": [
        {
          "ErrorEquals": ["Lambda.ServiceException", "Lambda.AWSLambdaException"],
          "Next": "HandleError"
        }
      ],
      "Next": "SuccessState"
    },
    "HandleError": {
      "Type": "Task",
      "Resource": "arn:aws:lambda:us-east-1:123456789012:function:sendErrorNotification",
      "Next": "FailState"
    },
    "SuccessState": {
      "Type": "Succeed"
    },
    "FailState": {
      "Type": "Fail"
    }
  }
}
```
✅ 処理の流れ
* Lambda関数が失敗 → リトライ (最大2回)
* それでも失敗 → HandleError に遷移

エラーハンドリング処理を行い、FailState に進む

## 🧷 Step Functionsで処理できるエラータイプ
AWS Step Functionsはさまざまなエラータイプに対応しています👇

### 🔥 Lambdaエラー
* Lambda.ServiceException：サービス側のエラー
* Lambda.AWSLambdaException：AWSの問題で失敗
* Lambda.TooManyRequestsException：スロットリング
### 🛠️ Taskエラー
* States.Timeout: タスクのタイムアウト
* States.TaskFailed: タスクが失敗
### 💾 DynamoDBエラー
* DynamoDB.ConditionalCheckFailedException
* DynamoDB.ProvisionedThroughputExceededException

## 🧷 エラー・リトライにおけるベストプラクティス
### ✅ リトライは最大回数とバックオフ率を設定する
* 無限にリトライし続けると無駄なコストと時間がかかる
* 指数バックオフでリトライ間隔を伸ばすのがオススメ
### ✅ エラーのログをCloudWatchに記録
* エラーハンドリング時にCloudWatch Logsに出力することでデバッグが容易に
### ✅ DLQ (デッドレターキュー)と連携
* 処理に失敗したイベントをSQSのDLQに送って後から手動で再処理するのも有効

## 🎉 まとめ
#### ✨ Step Functionsは「AWSサービスのオーケストレーションツール」！
* 処理フローを簡単に構築
* エラー処理やリトライが自動化
* GUIで視覚的に管理できる
* サーバーレスで手間いらず！
#### ✨ Step Functionsのエラー処理とリトライはめちゃ強力！
* リトライ：自動で再試行（回数・間隔・バックオフ調整可能）
* キャッチ：失敗時にエラーハンドリングへ分岐
* 組み合わせで信頼性の高いワークフローを構築
* デッドレターキューやCloudWatchと連携でさらに安定運用

## 💫 参考文献
* [AWS Step Functions](https://aws.amazon.com/jp/step-functions/)
* [AWS Step Functionsとは？各サービスをワークフローで連携](https://www.fujitsu.com/jp/products/software/resources/feature-stories/cloud-operation/workflow-linkage/)