🛤️

Rails 6(Puma)をsystemdの再起動に対応させる(Hot restart)

2023/05/12に公開

はじめに

Rails 5でPumaが標準のアプリケーションサーバーになりましたが、UnicornのままだったRails 6アプリをようやくPumaに変更したので公式で紹介されているsystemdで動かすようにしました。

このままではrestartのみでnginxのようなreloadに対応していないため、シャットダウン->起動となりサービスが瞬断されます。nginxのようにreloadに対応させて再読み込みしつつシャットダウンなしの再起動に対応します。具体的にはExecReloadを追加します。

環境はRails 6.1.7.3、Puma 5.6.5をAWS EC2のAmazon Linux2で動かしています。

設定ファイルの作成と必要なgemの追加

puma.service

/etc/systemd/systemに設定ファイルを作成します。

puma.service
[Unit]
Description=Puma HTTP Server
After=network.target

[Service]
Type=notify
# 公式の10秒では再起動中にwatchdogによってプロセスがkillされたので長めに
WatchdogSec=60
WorkingDirectory=<YOUR_APP_PATH>
PIDFile=<YOUR_APP_PATH>/tmp/pids/server.pid

# 必要な環境変数を指定
Environment="LANG=ja_JP.UTF-8"
Environment="RAILS_MAX_THREADS=20"
Environment="RAILS_ENV=production"

# tmp/pids/server.pidはconfig/puma.rbで指定されているもの
ExecStartPre=/usr/bin/rm -f <YOUR_APP_PATH>/tmp/pids/server.pid
ExecStart=/usr/local/rbenv/shims/bundle exec <YOUR_APP_PATH>/bin/rails server
# USR2シグナルを指定するとPumaはワーカーをリスタートします
ExecReload=/bin/kill -USR2 $MAINPID
Restart=always

[Install]
WantedBy=multi-user.target

再起動(systemctl reload puma)に対応させているので再起動中に500エラーにならずに再起動されるはずです(rails restartと同等なはず)。また、前段にnginxがある場合はPumaがシャットダウンされないため接続を維持します。

USR1では設定ファイルの再読み込みがないし、USR1を指定してもログを見ると

bundle[24680]: [24680] * phased-restart called but not available, restarting normally.

となっておりPhased restartされていなかったためUSR2にしています。

シグナルについてはこちらを

再起動についてはこちらを

sd_notify

puma.serviceType=notifyにしているのでsd_notifyが必要です。Gemfileに追加してbundle installします。

gem "sd_notify"

ちなみにPuma 6はsd_notify相当のコードが組み込まれているので不要です。

systemctlで起動する

systemdに登録し、

sudo systemctl daemon-reload

Pumaを開始します。

sudo systemctl start puma

状態の確認は

sudo systemctl status puma

サービス停止は

sudo systemctl stop puma

ソケットを維持して再起動(rails restartと同等)は

sudo systemctl reload puma

ソケットを維持せずにサービスの停止->開始での再起動は

sudo systemctl restart puma

Discussion