【AWS】S3の同一オブジェクトをトリガーに複数のLambdaを動かしたい！

## 1. はじめに

Amazon S3（S3）のイベントを基にAWS Lambda（Lambda）を起動したい場面はよくあります。
S3にはイベント通知機能があり、S3にデータがアップロードや削除されるなどのイベントをトリガーとして、LambdaやAmazon SQS（SQS）、Amazon SNS（SNS）に連携できます。

しかしながら、本記事執筆時点では、S3の同一オブジェクト（フォルダ）をトリガーとして**複数のイベント通知を設定することはできません**。

例えば、該当のオブジェクトをトリガーとして既にLambdaが設定されている場合や
データの後続処理が複数あり、並列して処理したい場合などがあります。

本記事では、以下について記載しております。

- S3から直接Lambdaを起動するパターン
- **S3の同一オブジェクトをトリガーとして、複数のLambdaを起動させたい場合のパターン**
- 各パターンの**メリット・デメリット、およびユースケース**


## S3からLambdaを直接起動するパターン

S3のイベント通知の設定で、直接Lambdaを連携させるパターンです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3717693/3c3bdb49-cbae-467c-a751-cdf2e1d3c465.png)

### メリット

- S3のイベント通知設定のみで、完了するため、構築が容易

### デメリット

- 同一オブジェクトをトリガーとする場合、複数のLambdaを起動することができません

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3717693/75b2be10-c582-4e94-977e-a43ebcd27d6c.png)

### ユースケース

- 特定のオブジェクトから1つのLambdaを起動させる場合


## 2. S3の同一オブジェクトを起点として複数のLambdaを起動するパターン

S3のイベント通知単体では、1つのLambdaしか起動できませんでしたが、以下のようなパターンでは、同一イベントから複数のLambdaを起動することが可能です
S3のイベント通知を利用し、同一オブジェクトに基づいて複数のLambdaを起動する方法には、主に以下の3つのパターンがあります。
個人的には「SQS + EventBridge Pipes」がおすすめです。

- パターン1：**SNS**
- パターン2：**EventBridge**
- パターン3：**SQS + EventBridge Pipes**


各パターンは、大きく以下のようなユースケースで分けることができます。

|パターンNo| 利用サービス       | ユースケース                              |
|---------|----------------|------------------------------------------|
| [パターン1](#3-パターン1-snsの利用)| SNS            | **Lambdaに渡す引数を変換しなくてよい場合** |
| [パターン2](#4-パターン2-eventbridgeの利用) | EventBridge    | **Lambdaに渡す引数を変換したい場合**     |
| [パターン3](#5-パターン3-sqs--eventbridge-pipes) | SQS + EventBridge Pipes | **エラーハンドリングもしたい・引数の変換もしたい**|

## 3. パターン1: SNSの利用

### 3.1 SNS単独利用

#### アーキテクチャ

S3のイベント通知をSNSに送信し、SNSから複数のLambdaを直接トリガーするパターンです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3717693/59c14d41-eb74-4632-bbd9-2a7ca67220ed.png)


#### メリット

- SNSとイベント通知の設定のみで簡単に試すことができます

#### デメリット

- SNSは数回の再試行は実施してくれますが、メッセージのバッファリング（長期間保持）ができないため、数回の再試行でLambdaが起動しない場合は、そのメッセージが削除されます
    - SNSのサブスクリプション設定でSQSを作成すればデットレターキューとして設定することは可能です

https://docs.aws.amazon.com/ja_jp/sns/latest/dg/sns-message-delivery-retries.html

:::note info

Lambdaのトリガーとして設定できるのはSNSのスタンダードタイプのみです
:::

https://docs.aws.amazon.com/ja_jp/lambda/latest/dg/with-sns.html

- SNSのFIFOタイプはアーカイブ機能ががありますが、Lambdaのトリガーとして利用できません

https://docs.aws.amazon.com/ja_jp/sns/latest/dg/message-archiving-and-replay-topic-owner.html

- Lambdaに渡す引数を変換することができません

#### ユースケース

- 簡易的なテストとして、素早くLambdaの動作確認をしたい場合
- 小規模な処理で、エラーハンドリングの要件が低い場合

### 3.2 SNS + SQSの利用

#### アーキテクチャ

SNSとSQSを組み合わせることで、SNSのメッセージをSQSにキューイングし、SQSからLambdaをトリガーする形にします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3717693/c11980a0-e7c9-4770-97fe-b05e9fc9f519.png)

#### メリット

- SQSはSNSと異なり、バッファリング（長期保存）が可能です（60秒から14日間まで設定可能）

https://docs.aws.amazon.com/ja_jp/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-configure-queue-parameters.html

- デッドレターキュー（DLQ）を活用し、メッセージの処理失敗時に再試行可能です

#### デメリット

- SNS単体同様、SQS内でLambdaに渡す引数を変換することができません

#### ユースケース

- S3イベントが大量に発生する場合
    - 例：基幹システムからS3へ1秒間に数百ファイルがアップロードされる場合

- エラーハンドリングが重要な場合（リトライやDLQ管理）

#### 補足

- 1つのデータ量が重い場合は、Lambdaのメモリや実行時間の延長などが必要です

## 4. パターン2: EventBridgeの利用

### 4.1 EventBridge単独利用

#### アーキテクチャ

S3のイベント通知をEventBridgeに送信し、EventBridgeルールを使用して複数のLambdaを起動させます

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3717693/871b37bf-f571-4e19-8db4-c454cc090b95.png)


#### メリット

- 引数変換が可能です

EventBridgeのルール機能を使用して、Lambdaに渡す引数を柔軟に変換することができます。

#### デメリット

- エラーハンドリングをLambda側で実装する必要があります

- 複雑な処理フロー（ワークフロー制御）は困難です

複雑な処理を実装する場合は、Step Functionsを利用しましょう。

- SNS同様バッファリングがありません。ただし、リトライ回数を指定することが可能です
    - EventBridgeからSQSを介してLambdaを実装することも可能ですが、[補足](#補足)に記載しているパターンの方がおすすめです

#### ユースケース

- Lambdaが単純な並列処理の場合  
例えば、Lambda（A）とLambda（B）が独立した処理を行っている場合です

- Lambdaの処理順序や条件分岐を制御しなくていい場合
  - 以下の場合はStep Functionsを利用しましょう
  - Lambda（A）のあとにLambda（B）を実行するなど順番を制御する場合
  - 変数AがtrueであればLambda（A）を動かす、falseであればLambda（B）を実行

### 4.2 EventBridge + Step Functionsの利用

#### アーキテクチャ

EventBridgeをトリガーにして、Step Functionsを利用して実行順序や条件分岐を制御しながら、Lambdaを起動させることが可能です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3717693/8ec8b9e8-e7af-4992-9df8-daeda95f0185.png)

#### メリット

- 複雑なワークフロー管理が可能
- エラーハンドリングやリトライ管理が容易
- 可視化がしやすく、監視が容易

#### デメリット

- Step Functionsの利用に応じた追加コストがかかる

https://aws.amazon.com/jp/step-functions/pricing/

#### ユースケース

- Lambdaの実行順序を制御したい場合
- 複雑なワークフローを実装したい場合

### 5. パターン3: SQS + EventBridge Pipes

### アーキテクチャ

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3717693/595a81f5-1084-4e0a-94a5-015bc64d04ce.png)

SQSのバッファリング機能に加えて、Lambdaに渡す引数をEventBridge Pipesで変換することが可能です。

https://docs.aws.amazon.com/ja_jp/eventbridge/latest/userguide/eb-pipes.html

### メリット
- SQSのバッファリング機能を活用可能
- EventBridge Pipesで引数変換が可能
- エラーハンドリングが容易

### デメリット
- 構成がやや複雑になる

### ユースケース
- 引数変換が必要で、エラーハンドリングも重要な場合
- 大量のイベント処理が必要な場合
    - 例えば、基幹システムからS3へ1秒間に数百ファイルが出力される場合

## 6. まとめ

個人的には、SQSからEventBridge Pipesを介してLambdaを呼ぶパターンが、さまざまな運用面を考慮するとよいのではないかと考えています。  

以下に機能面と条件・要件面での各パターンのまとめを記載します。
コメントにみなさまの意見を記載してもらえると大変参考になります。


### 条件・要件面

| 条件                                             | パターン                          |
|--------------------------------------------------|---------------------------------------|
| Lambdaに渡す引数を変換したい場合                 | EventBridge                           |
| 複雑なワークフローを管理したい場合               | EventBridge + Step Functions           |
| Lambdaに渡す引数を変換しない場合かつ、お試しでLambdaを実行したい場合           | SNS                                   |
| 引数を変換しないかつ、エラーハンドリングが重要な場合 | SNS + SQS（DLQ活用）                   |
| Lambdaに渡す引数を変換したいかつ、エラーハンドリングが重要な場合 | SQS + EventBridge Pipes               |


### 機能面

| 機能軸               | SNS               | SNS + SQS          | EventBridge       | EventBridge + Step Functions | SQS + EventBridge Pipes |
|-----------------------|-------------------|-------------------|-------------------|-----------------------------|-------------------------|
| **到達性**     | At least once    | At least once    | At least once    | At least once              | At least once          |
| **配信の信頼性**     | At least once    | At least once    | At least once    | At least once              | At least once          |
| **リトライ可否**     | 可能（設定簡単）  | 可能（DLQ活用）   | 可能（設定簡単）  | 可能（Step Functionsで制御）| 可能（DLQ活用）        |
| **バッファリング**   | なし              | 最大14日間        | なし              | なし                       | 最大14日間             |
| **スケーラビリティ** | 高い              | 高い              | 高い              | 高い                       | 高い                   |
| **メッセージの変換** | なし              | なし              | 可能（ルール設定）| 可能（Step Functionsで制御）| 可能（Pipesで変換）    |
| **エラーハンドリング** | DLQ設定可能       | DLQ設定可能       | DLQ設定可能       | DLQ設定可能もしくはStep Functionsで制御可能   | DLQ設定可能            |
| **監視と可視化**     | CloudWatch対応    | CloudWatch対応    | CloudWatch対応    | CloudWatch + Step Functions可視化 | CloudWatch対応   |

## 7. 注意点

- S3のイベント通知やEventBridgeはFIFO（順序保証）をサポートしておりません
- S3のイベント通知やEventBridgeは「少なくとも1回実行」のため、同一イベントが複数回実行される場合があります。そのため、処理によってはLambda側で冪等性を考慮する必要があります。  

https://aws.amazon.com/jp/blogs/storage/manage-event-ordering-and-duplicate-events-with-amazon-s3-event-notifications/