AWS SQS sendMessageBatchとdeleteMessageBatchの処理の仕様について

### はじめに
先日AWSのSQSを使ってSQS内にあるメッセージを別のキューに送信した後に元のキューの処理済みメッセージを削除するシステムを構築した際に、そこで使用されていた２つのメソッドを検証したところ、要注意な仕様があったのでここにまとめておく。

# 目次
**1. そもそもsendMessageBatch・deleteMessageBatchとは？**
 * sendMessageBatchとは？
 * deleteMessageBatchとは？

**2. 気をつけなければいけない仕様とは？**
 * 一部処理に失敗しても、ステータスコード200が返ってくる場合がある
 * 特にこのケースには要注意

**3. 一部処理に失敗したときに処理を分けるには？**
* Failedを活用する



## そもそもsendMessageBatch・deleteMessageBatchとは？

### sendMessageBatchとは？
* 数多く存在するAWSのSQSに存在するメソッドの中の一つ。（参照：[JavaScript API リファレンス](https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/SQS.html)

* 指定されたキューに対して最大１０個のメッセージを送信するというもの。

* 似たようなものにメッセージを一件だけ送信するsendMessageが存在するが、そのバッチ処理バージョンがこれ。

* このメソッドを呼び出すと、以下のように送信に成功したメッセージを失敗したメッセージをリストで返してくれる。
~~~javascript:sendMessageBatchの結果
 SendMessageBatchResult {    //送信結果のオブジェクト
      Successful: SendMessageBatchResultEntryList;  //送信に成功したメッセージのリスト
      Failed: BatchResultErrorEntryList;  //送信に失敗したメッセージのリスト
 }
~~~
*****
### deleteMessageBatchとは？
* このメソッドも数多く存在するAWSのSQSに存在するメソッドの中の一つ。（参照：[JavaScript API リファレンス](https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/SQS.html)

* 指定されたキューから最大１０個のメッセージを削除するというもの。

* このメソッドも似たようなものにメッセージを一件だけ送信するdeleteMessageが存在するが、そのバッチ処理バージョンがこれ。

* このメソッドを呼び出すと、以下のように削除に成功したメッセージを失敗したメッセージをリストで返してくれる。
~~~javascript:deleteMessageBatchの結果
DeleteMessageBatchResult {   //削除結果のオブジェクト
    Successful: DeleteMessageBatchResultEntryList;   //削除に成功したメッセージのリスト
    Failed: BatchResultErrorEntryList;   //削除に失敗したメッセージのリスト
}
~~~
*****
## 気をつけなければいけない仕様とは？
### 一部処理に失敗しても、ステータスコード200が返ってくる場合がある
* 注意しなければいけないのは、この二つのメソッドはバッチ処理で、まとめて処理するものであるということ。

* そのため仮に10件処理したとして、そのうち２件なんらかの原因で処理に失敗したとしてもエラーが発生せず、ステータスコード２００が返ってくる場合がある。

### 特にこのケースには要注意

* 例えば、sendMessageBatchであるSQSにメッセージを10件送信した後にそのSQSからそれらのメッセージdeleteMessageBatchで削除するとする。

* その場合、それぞれのメソッドは一部失敗したとしてもエラーにならないので、仮にsendMessageBatchに一部失敗したとしても、deleteMessageBatchで全件成功してしまう可能性がある。

* つまり、「送信に失敗したのに削除されてしまったメッセージ」が存在してしまうことになる。

↓↓↓こんな感じ↓↓↓
~~~javascript:一部処理に失敗してもエラーにならない
//たとえばtry~catchなどで例外処理をしてもcatchされない可能性がある
try{
    //sendMessageBatchは一部処理に失敗しても処理が続行され、エラーがでない
    var sendMessageBatchResult = sqs.sendMessageBatch(キューのURL, 送信対象のメッセージリスト);

    //sendMessageBatchで一部処理に失敗しても、以下の処理は実行される
    var deleteMessageBatchResult = sqs.deleteMessageBatch(キューのURL, 削除対象のメッセージリスト);
    
}catch(e){
    console.log("エラー");
}
~~~
*****
## 一部処理に失敗したときに処理を分けるには？
* デフォルトではエラーは出されない仕様なので、それぞれのメソッドが返してくれるオブジェクト内の失敗リスト（Failedリスト)を活用する

↓↓↓こんな感じ↓↓↓
~~~javascript: エラー処理の例
//sendMessageBatchを実行して変数sendResultに代入
var sendResult = sqs.sendMessageBatch(キューのURL, 送信対象のメッセージリスト);

if(sendResult.Failed.length != 0){  //リストFailedの長さが0でなければ一部処理が失敗している
    throw new Error('一部送信に失敗しました');
}else{
    console.log("全件成功しました");
}

//deleteMessageBatchも同様
var deleteResult = sqs.deleteMessageBatch(キューのURL, 処理対象のメッセージ);

if(deleteResult.Failed.length != 0){  //
    throw new Error('一部削除に失敗しました');
}else{
    console.log("全件成功しました");
}
~~~
* sendResult.Failed.lengthとdeleteResult.Failed.lengthにはそれぞれの失敗件数が格納される
* これを活用すれば、何件処理に成功または失敗しているのかを表示させることも可能
　
* また、sendMessageBatchで処理成功したメッセージリストだけをdeleteMessageBatchの対象にすれば、先ほどの「送信には失敗したけど削除には成功したメッセージ」を回避することができる
↓↓↓こんな感じ↓↓↓
~~~javascript:一部処理に失敗してもエラーにならない
//sendMessageBatchは一部処理に失敗しても処理が続行され、エラーがでない
var sendMessageBatchResult = sqs.sendMessageBatch(キューのURL, 送信対象のメッセージリスト);

//sendMessageBatchで成功したメッセージだけを削除対象にすれば、送信に失敗したものが削除されることはない
var deleteMessageBatchResult = sqs.deleteMessageBatch(キューのURL, sendMessageBatchResult.Successful);
~~~