👻

本番環境で504 Gateway Time-outが出た

2024/09/04に公開

ブラウザに表示されたエラー

504 Gateway Time-out

何が起きている?

504 Gateway Time-outは2つのサーバーがあって、1つのサーバーがもう一方のサーバーからの応答を待っている間にタイムアウトが発生している。


今回の場合、Apacheをリバースプロキシとして設定している。

処理の流れが以下のようになる。

  1. ブラウザからApacheコンテナにリクエストが送られる
  2. ApacheコンテナからRailsコンテナに転送される
  3. RailsコンテナがApacheコンテナにレスポンスを返す
  4. Apacheコンテナからブラウザに返す

上記の3のところで時間がかかりすぎてタイムオーバーになっている。

Railsからの応答のタイムアウトはどこで設定する?

config/puma.rbの中でworker_timeout 秒数と設定する。
何も書かないとデフォルトでは60秒に設定されている。

config/puma.rb
# すべての環境で共通
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でコンテナを構築していて、以下のように本番環境をしている。

docker-compose.prod.yaml
services:
  rails:
    environment:
      - RAILS_ENV=production

そのため、if ENV.fetch('RAILS_ENV', 'production') == 'production'trueになり、本番環境ではタイムアウト300秒が反映される。

追記(上記をやってもまだ504が出た)

config/puma.rb
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_ENVdevelopmentが代入されて、本番環境のタイムアウト設定が効かなくなった?
→いや、でも第2引数が代入されるのはRAILS_ENVが設定されてない場合だからおかしい
RAILS_ENVprocutionが入っていない?
RAILS_ENVの中身を確認したい

試したこと

EC2に手動でログインして
sudo docker exec -it コンテナID bashでRailsコンテナにログインして
echo ${RAILS_ENV}で確認したら
productionと表示された。

ということは、puma.rbは修正する必要がなさそうだ。

次に試したこと

ロードバランサーのタイムアウト設定を変更した。
デフォルトで1分のところを5分にした。

何回か試して今のところエラーは出ていない。

参考文献

https://kinsta.com/jp/blog/504-gateway-timeout/
https://docs.ruby-lang.org/ja/latest/method/ENV/s/fetch.html

Discussion