AWS Step Functionsを活用したバッチ処理とキュー管理について

# はじめに
`AWS - Step Functions`のバッチ処理と `queue` 管理の相関性についてまとめたいと思います。

# 全体的な処理の流れについて

まずは、ジョブとプロセスの概要を押さえるために、処理の流れに沿ってまとめます。

## `Step Functions`を使用したバッチ処理フロー

### 1. イベントの発生
バッチ処理をトリガーするイベントが発生を起点にします。
※ 定期的なスケジュール（例えば、毎日1回）や特定の条件を満たしたときにトリガーされるように設定されていることが多い
これを設定するためには、`Amazon CloudWatch Events`や`Amazon EventBridge`を使用することが多いです。

### 2. ジョブの生成

イベントが発生すると、新しいバッチジョブが生成される。
このジョブは、特定のタスクの集まりとして定義され、これらのタスクを実行するための一連のステップのことを指します。

### 3. `Step Functions`の開始

ジョブが生成された後、`AWS Step Functions`のステートマシンが開始されます。
このステートマシンはジョブを実行するためのワークフローを定義しています。

### 4. データの取得

最初のタスクとして、ジョブはデータ取得プロセスを開始します。
このプロセスでは、`Amazon S3`からファイルを取得する、データベース（例えば、`Amazon RDS`や`Amazon DynamoDB`）からデータを取得するなどの方法があります。

### 5. データの処理

データ取得プロセスが完了すると、次にデータ処理プロセスが開始されます。
このプロセスは、`Lambda`関数や`ECS`タスクなどを使用して実行され、データの変換、フィルタリング、集計などの操作が行われます。

### 6. キューに積む

データ処理プロセスが完了すると、ジョブはデータを`Amazon SQS queue`に積むタスクへ進みます。
これは、`Lambda`関数や`Step Functions`のビルトインタスクを使用して実行されます。

### 7. `Queue Worker`による処理

キューに積まれたデータは、`Queue Worker`によって処理されます。
`Queue Worker`は、キューに積まれたタスクをバックグラウンドで処理するプロセスです。
これらのワーカーは、例えばジョブキューやメッセージキューからタスクを取り出し、順次処理します。

キューシステム（例えば、`Amazon SQS`や`RabbitMQ`）と連携して動作し、スケーラブルな非同期処理を実現します。

### 8. エラーハンドリング

ジョブの実行中にエラーが発生した場合、エラーハンドリングプロセスが開始されます。
`Step Functions`では、リトライやキャッチブロックを使ってエラー処理を定義することができます。

### 9. ジョブの終了

全てのタスクが完了したら、ジョブは終了します。
必要に応じて、終了後のクリーンアップタスク（例えば、ログの保存や通知の送信）を実行します。

## `ECS`と`supervisord`のメモリについて

### `ECS`のメモリ上限と`supervisord.conf`で`queue worker`のメモリ上限それぞれで引っかかってしまった時のキルについて

#### `ECS`のメモリ上限
`ECS`のメモリ設定は、コンテナ全体に対して割り当てられるメモリリソースを指定します。
各タスク定義において、必要なメモリ量を設定し、`ECS`はこのメモリ制約に基づいてコンテナをスケジューリングします。
コンテナが割り当てられたメモリを超過すると、`ECS`はそのコンテナを停止（キル）します。

#### `supervisord.conf`で設定される`queue worker`のメモリ上限
`supervisord.conf`で設定されるメモリは、個々のプロセスやワーカーに対して適用されます。
これは、プロセスが使用するメモリの上限を制御するために設定されることがあり、特定のプロセスがシステム全体に過度な負荷をかけないようにするためのものです。
プロセスがこのメモリ上限を超過すると、`supervisord`はそのプロセスを停止（キル）します。

#### メモリ上限に引っかかった時のキルについて
`ECS`のメモリ上限と`supervisord.conf`で設定されたメモリ上限は、異なるレベルでリソースを管理します。
`ECS`のメモリ上限に達した場合、コンテナ全体が停止されます。
一方、`supervisord.conf`で設定されたメモリ上限に達した場合は、個々のプロセスが停止されます。
これにより、特定のプロセスだけを再起動して問題を解決できる場合もあれば、コンテナ全体の再起動が必要となる場合もあります。

## `queue` のメッセージとそれらがある状態のコンテナの停止時や更新時の挙動について

### キューで積まれる処理中のメッセージと待機中のメッセージ

#### 処理中のメッセージ

処理中のメッセージは、`Queue Worker`が取得し、現在処理しているメッセージです。
これらのメッセージは一時的にキューから取り出されており、処理が完了するか、一定時間が経過するまで再度キューに戻されることはありません。
`Amazon SQS`では、これを「`Visibility Timeout`（= 可視化性タイムアウト）」として管理しています。

#### 待機中のメッセージ

待機中のメッセージは、キューに積まれたまま処理を待っているメッセージです。
これらのメッセージは、`Queue Worker`が取得するまでキュー内に保持されます。

### キューのコンテナの停止や更新時の動き

#### 処理中のメッセージがある場合

キューのコンテナが停止または更新されると、処理中のメッセージは一時的に失われる可能性があります。
それらを防ぐ方法としては、以下などがあります。

- `Visibility Timeout`の設定
    - メッセージの`Visibility Timeout`を適切に設定することで、処理中にコンテナが停止した場合でも、一定時間後に再度キューに戻され、再処理されるようにする
- 処理の冪等性
    - `Queue Worker`がメッセージを再処理する際に問題が発生しないように、処理を冪等性（同じメッセージを何度処理しても結果が変わらない）にする

#### 待機中のメッセージがある場合

キューのコンテナが停止または更新されても、待機中のメッセージはキューに保持され続けます。
コンテナが再起動または新しいバージョンに更新された後、`Queue Worker`は再びメッセージを取得して処理を再開します。

## その他の単語の解説

### プロセスとは
プロセスとは、コンピュータプログラムが実行中のインスタンスです。
プロセスは、プログラムコード、データ、システムリソース（メモリ、ファイルディスクリプタなど）を含みます。

### プロセスのキルとは
プロセスのキルとは、実行中のプロセスを強制的に終了させる操作です。
これは通常、`kill`コマンドを使用して行われ、特定のシグナルをプロセスに送信することで実現します。

### `Queue Worker`とは
`Queue Worker`とは、キューに積まれたタスクをバックグラウンドで処理するプロセスのことです。
これらのワーカーは、例えばジョブキューやメッセージキューからタスクを取り出し、順次処理します。

### `Supervisord`とは
`Supervisord`とは、`UNIX`系システムでプロセス管理を行うためのツールです。
複数のプロセスを一元管理し、自動的に起動・再起動・停止を行うことができます。

### `supervisord.conf`とは
`supervisord.conf`とは、`Supervisord`の設定ファイルです。
このファイルには、管理するプロセスの定義、ログの設定、再起動ポリシーなどが記述されています。
設定ファイルを編集することで、`Supervisord`の動作をカスタマイズすることができます。

## `ECS`のメモリと`supervisord.conf`で設定されている`Queue Worker`のメモリの違い
`ECS`のメモリと`supervisord.conf`で設定されている`Queue Worker`のメモリは、異なるレベルでリソースを管理します。

- `ECS`のメモリ
    - `ECS`のメモリ設定は、コンテナ全体に対して割り当てられるメモリリソースを指定
    - 各タスク定義において、必要なメモリ量を設定し、`ECS`はこのメモリ制約に基づいてコンテナをスケジューリングされる

- `supervisord.conf`で設定されている`Queue Worker`のメモリ
    - `supervisord.conf`で設定されるメモリは、個々のプロセスやワーカーに対して適用される
    - これは、プロセスが使用するメモリの上限を制御するために設定されることがあり、特定のプロセスがシステム全体に過度な負荷をかけないようにする

つまり、`ECS`のメモリ設定はコンテナレベルでの管理であり、`supervisord.conf`の設定はプロセスレベルでの管理です。

# 最後に
`queue` のメッセージ中のコンテナ停止時 / 更新時の動きを改めて言語化したことで、より解像度が上がったと思います。
今後ともインフラ領域の知見を広げていきたいです。