本番環境で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