AWS Elastic Beanstalk の worker 環境でエラー検知する

AWS Elastic Beanstalk で実行時間が比較的長いタスクを処理したい場合、専用の worker 環境にタスクをオフロードすることができます。
この記事では worker 環境でのタスクの処理に失敗した際のエラー検知を設定する方法についてメモします。

## Elastic Beanstalk の worker 環境について

worker 環境は Amazon SQS キューからアイテムを取得するデーモンプロセスである sqsd と内部的に web サーバーを持つアプリケーションの2つで構成されます。
sqsd は取得したアイテムを `http://localhost:80` に POST し、アプリケーションにタスクを処理させます。
アプリケーションから 200 レスポンスが返ってくればメッセージをキューから削除し、 200 以外のレスポンスが返ってくればキューにタスクを積み直してくれます。

<img width="713" alt="Screen Shot 2020-04-19 at 23.25.44.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/179455/bf9c4ebf-8d46-46d5-58bc-a2e46f24ca88.png">

<cite>[Elastic Beanstalk ワーカー環境 \- AWS Elastic Beanstalk](https://docs.aws.amazon.com/ja_jp/elasticbeanstalk/latest/dg/using-features-managing-env-tiers.html)</cite>

さて、アプリケーションから 4xx や 5xx のレスポンスが返ってきた場合のエラー検知ですが、 web server 環境とは少し異なる方法を考える必要があります。
web server 環境では Application Load Balancer のメトリクス `HTTPCode_Target_5XX_Count` に対してしきい値を設定することでエラー検知が可能です。
一方の worker 環境では Application Load Balancer が設定されないため、別のメトリクスを採用する必要があります。

## エラー検知の設定

前述の通り worker 環境は内部で web サーバーを使用しているため、 CloudWatch で web サーバーの 5xx のログをカウントするようなメトリクスを作成することができます。
このカスタムメトリクスに対してアラートを設定すればエラー検知できるという寸法です。

以下は Apache を web サーバーとして利用する場合の例です。

### メトリクスフィルターの作成

worker 環境の Apache のロググループを選択し、さらに「メトリクスフィルターを作成」を選択します。

![create_metrics_filter_edited.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/179455/10ac1b40-cb68-984b-a289-c2ccea58163d.png)

最初のステップの「パターンを定義」の「フィルターパターンを作成」で、ステータスコード 5xx のログに一致するパターンを設定します。
ここでは専用の[パターン構文](https://docs.aws.amazon.com/ja_jp/AmazonCloudWatch/latest/logs/FilterAndPatternSyntax.html)を使用することができ、複雑な正規表現を書かなくてもある程度自由度の高いパターン記述が可能です。

<img width="792" alt="Screen Shot 2020-04-19 at 21.37.41.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/179455/4226e6f2-309d-464c-9d61-2af58a017996.png">


例えば以下のようなログを想定してみます。

```
127.0.0.1 (-) - - [16/Apr/2020:01:23:45 +0900] "POST /worker/queue HTTP/1.1" 200 1234
127.0.0.1 (-) - - [16/Apr/2020:12:34:56 +0900] "POST /worker/queue HTTP/1.1" 200 2345
127.0.0.1 (-) - - [17/Apr/2020:01:23:45 +0900] "POST /worker/queue HTTP/1.1" 500 1234
```

この場合は以下のようなパターン構文で 5xx エラーをカウントできます。

```
[ip, global_ip, user, username, timestamp, request, status_code = 4** || status_code = 5**, ...]
```

あとは適切にメトリクス名や値を設定すればカスタムメトリクスの作成は完了です。

<img width="802" alt="1_3_confirm_mosaic.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/179455/fcdf55ee-2d06-7622-6adf-1e0a18247ca8.png">


あとは引き続き CloudWatch でこのメトリクスを使ってアラートを作成すればエラー検知ができます。

## 今後の課題

この設定方法は Apache のログ形式に依存しているため、ログの出力方式が変わると動作しなくなる可能性があります。

実は Elastic Beanstalk の拡張ヘルスレポートとして ApplicationRequests5xx というカスタムメトリクスを CloudWatch にパブリッシュする機能もあり、当初はこれを利用する予定でした。

> `ApplicationRequestsTotal`
> `ApplicationRequests5xx`
> `ApplicationRequests4xx`
> `ApplicationRequests3xx`
> `ApplicationRequests2xx`
> インスタンスと環境が対象。 インスタンスまたは環境で完了したリクエストの総数と、各ステータスコードカテゴリで完了したリクエストの数を示します。
> 
> <cite>[環境の Amazon CloudWatch カスタムメトリクスのパブリッシュ \- AWS Elastic Beanstalk](https://docs.aws.amazon.com/ja_jp/elasticbeanstalk/latest/dg/health-enhanced-cloudwatch.html)</cite>

しかし実際のリクエスト数とカウント数が一致しない事象が発生したため、今回はこのメトリクスの使用を断念しています。
このメトリクスが利用できると環境への依存度も小さくなるので、メトリクスの仕様についてもう少し詳しく調べていきたいところです。