本番環境で504 Gateway Time-outが出た
ブラウザに表示されたエラー
504 Gateway Time-out
何が起きている?
504 Gateway Time-outは2つのサーバーがあって、1つのサーバーがもう一方のサーバーからの応答を待っている間にタイムアウトが発生している。

今回の場合、Apacheをリバースプロキシとして設定している。
処理の流れが以下のようになる。
- ブラウザからApacheコンテナにリクエストが送られる
- ApacheコンテナからRailsコンテナに転送される
- RailsコンテナがApacheコンテナにレスポンスを返す
- Apacheコンテナからブラウザに返す
上記の3のところで時間がかかりすぎてタイムオーバーになっている。
Railsからの応答のタイムアウトはどこで設定する?
config/puma.rbの中でworker_timeout 秒数と設定する。
何も書かないとデフォルトでは60秒に設定されている。
# すべての環境で共通
worker_timeout 300
# もともとこれが書いてあった
worker_timeout 3600 if ENV.fetch('RAILS_ENV', 'development') == 'development'
# 本番環境のタイムアウトを追加した
worker_timeout 300 if ENV.fetch('RAILS_ENV', 'production') == 'production'
すでにdevelopmentの設定があったので、本番環境のタイムアウト設定を追加した。
ENV.fetchとは?
fetch(key, default)
第1引数には環境変数の名前が入る。
第2引数のdefaultには、第1引数keyに対応する環境変数の値がないときにこの値を返す。
今回、Dockerでコンテナを構築していて、以下のように本番環境をしている。
services:
rails:
environment:
- RAILS_ENV=production
そのため、if ENV.fetch('RAILS_ENV', 'production') == 'production'がtrueになり、本番環境ではタイムアウト300秒が反映される。
追記(上記をやってもまだ504が出た)
worker_timeout 3600 if ENV.fetch('RAILS_ENV', 'development') == 'development'
worker_timeout 300 if ENV.fetch('RAILS_ENV', 'production') == 'production'
# 中略
environment ENV.fetch('RAILS_ENV', 'development')
考えたこと
最後の行で、RAILS_ENVにdevelopmentが代入されて、本番環境のタイムアウト設定が効かなくなった?
→いや、でも第2引数が代入されるのはRAILS_ENVが設定されてない場合だからおかしい
→RAILS_ENVにprocutionが入っていない?
→RAILS_ENVの中身を確認したい
試したこと
EC2に手動でログインして
sudo docker exec -it コンテナID bashでRailsコンテナにログインして
echo ${RAILS_ENV}で確認したら
productionと表示された。
ということは、puma.rbは修正する必要がなさそうだ。
次に試したこと
ロードバランサーのタイムアウト設定を変更した。
デフォルトで1分のところを5分にした。

何回か試して今のところエラーは出ていない。
参考文献
Discussion