レスポンスが返ってくることのありがたみ
今回のお話
ブラウザ → フロントエンドサーバー → バックエンドサーバー → たまに別のAPIサーバー という構成で、ブラウザからあるURLにリクエストを送信したところ、504 Gateway Timeout がレスポンスとして返ってきたときのトラブルシューティングです。
先に3行まとめ
- レスポンスが返ってこないことだってたまにあるよ
- セキュリティグループに通信が弾かれると、レスポンスは返ってこない
- 他のAPIへの通信は適切にタイムアウト時間を設定しよう
ECS で稼働する環境
- フロントエンドサーバー と バックエンドサーバー をまとめて1つのサービスタスクとしていた
- 別のAPIサーバーは 別のサービスタスクとして起動
- バックエンドサーバー から 別のAPIサーバー へリクエストを送信するときはサービス検出の仕組みを使っていた

サービス検出についてはこちらで詳しく書いています
発生した問題
画面からあるボタンを押したところ、しばらく時間が立ってから 500 Internal Server Error が画面に表示されました。
調査
Chrome DevTools のネットワークタブで詳細を確認したところ、あるエンドポイントへのリクエストに時間がかかっており、最終的に 504 Gateway Timeout がレスポンスとして返ってきていることがわかりました。504 Gateway Timeout だったので、フロントエンドではエラーハンドリングできておらず、500 Internal Server Error が表示されてしまったというような状況です。
負荷が高い?
このエンドポイントは確かに重い処理を行うことがあり、DBへの負荷が高くバックエンドサーバーでタイムアウトを起こしているのではと考えました。
しかし、このエンドポイント以外でも同じような挙動が起きている箇所もあり、負荷が原因ではないと判断しました。
APIサーバーへの通信が怪しい?
他に原因として考えられることがあるか実装をよく確認しなおしたところ、他のAPIサーバーに通信を行っており、この問題が発生しているエンドポイントに共通する点でした。そのため、この点を深ぼってみることにしました。
しかし、
- APIサーバーへの通信が失敗すると、エラーをキャッチして適切に処理するような実装となっている
- ローカル環境で動作確認を行うと、504 Gateway Timeout は発生しない、即レスポンスが返ってくる
という状況でしばらく頭を悩ませました。
ローカル環境との差分を確認したところ、APIサーバーへリクエストを出す時のURLの違いに気づきました。ローカル環境では特に指定はしておらず、実環境では実際に存在するURL(サービス検出で使用しているCloud Mapが発行するURL)にリクエストを出しています。
ここで「これレスポンス何も返ってきていないのでは?」と気づきます。
そうです。あいつのせいです、セキュリティグループ。

バックエンドサーバーからの通信をAPIサーバーのセキュリティグループのインバウンドルールで許可していませんでした(訳あって許可していない)。
なのでサービス検出自体はうまくいっており、DNS名前解決までされているがセキュリティグループのインバウンドルールで弾かれているというオチです。レスポンスが何も返ってこないため、バックエンドでしばらく待っていたが、フロントエンドでタイムアウトが発生し、504 Gateway Timeout を返していたということです。
解決方法
バックエンドではAPIサーバーにリクエストを送信する時にタイムアウト時間が設定されていませんでした。
なのでバックエンドでは適切にタイムアウト時間を設定したうえで、APIサーバーにリクエストを送信します。フロントエンドのタイムアウト時間より余裕を持ったタイムアウト時間を設定しておくと安心です。
今回は内部の自前のAPIサーバーへの通信の話でしたが、外部APIでも適切にタイムアウトは設定したいですね。
まとめ
通信がうまくいかない = 大体セキュリティグループの設定がミスってる
というのをまた噛み締めた今日この頃でした。
日常会話でもHTTPリクエストでもレスポンスは返ってくると嬉しいですよね。
Discussion