Gemにcapistrano3-delayed-jobがあるのですが、service作る形になっていて、sudoで設定が必要だったり(セキュアにする為、アプリユーザーのsudoはできないようにしている)、OSに依存しそうなので、自前で組んでみました。
seed作った時と同じ要領なので、難しくないですがメモしておきます。
アプリユーザーのcrontabで、サーバー再起動時の自動起動や、落ちた時に自動起動するcronも書いたので一緒に記載しておきます。
Capistranoの設定変更
Capistranoの設定は完了している前提です。
→ Capistranoを設定して安全にデプロイできるようにする
config/deploy/production.rb
- server 'prod-servername_railsapp', roles: %w[app db web] + server 'prod-servername_railsapp', roles: %w[app db web job]
rolesにjob追加。appでも良いけど、複数台にした時の為。
config/deploy.rb
after 'unicorn:restart', 'delayed_job:restart'
Unicornの再起動後に、Delayed::Jobを再起動する。
namespace :delayed_job do desc 'Runs bin/delayed_job status' task :status do execute_delayed_job('status') end desc 'Runs bin/delayed_job start' task :start do execute_delayed_job('start') end desc 'Runs bin/delayed_job stop' task :stop do execute_delayed_job('stop') end desc 'Runs bin/delayed_job restart' task :restart do execute_delayed_job('restart') end end def execute_delayed_job(arg) on roles(:job) do within release_path do execute :ruby, 'bin/delayed_job', arg end end end
deployで使うのはrestartだけですが、capコマンドでstatus/start/stopもできるように追加。
動作確認
ローカルで
% cap -T cap delayed_job:restart # Runs bin/delayed_job restart cap delayed_job:start # Runs bin/delayed_job start cap delayed_job:status # Runs bin/delayed_job status cap delayed_job:stop # Runs bin/delayed_job stop % cap production delayed_job:status 01 delayed_job: running [pid 8067] % cap production deploy 01:23 delayed_job:restart 01 ~/.rvm/bin/rvm ruby-3.0.0 do ruby bin/delayed_job restart 01 delayed_job: trying to stop process with pid 4503 sending TERM and waiting 20s ... 01 delayed_job: process with pid 4503 successfully stopped. 01 delayed_job: process with pid 8067 started. ✔ 01 prod-nop_railsapp 9.182s
crontab設定
service作らなかったので、サーバー再起動時に起動されない。
Unicornもアプリユーザーのcronで起動するようにしているので、そこに追加しました。
サーバーで
$ crontab -e
@reboot bash -l -c 'cd ~/app/current/; rm -f tmp/pids/{unicorn,delayed_job}.pid; bundle exec rails unicorn:start; bin/delayed_job start' */10 * * * * bash -l -c "~/app/current/cron/start_delayed_job.cron"
また、Unicornは外部監視で落ちた事に気付けるけど、Delayed::Jobは内部監視を入れないと気付けない。内部監視を別途入れるのは手間だし、落ちた時に対応するのも手間なので、cronを作る事にしました。(上記の2行目)
※Unicornも何度か落ちましたが、原因(php-fpmがメモリ使い過ぎ)に対処したので、様子見。
cron/start_delayed_job.cron
#!/bin/sh BATCH_NAME='start_delayed_job' LOG_FILE="log/$BATCH_NAME.log" cd ~/app/current error_msg='' write_log () { echo -e "`date +"%Y/%m/%d %H:%M:%S"` ($$) [$1] $2" >> $LOG_FILE [ $1 = 'ERROR' -o $1 = 'WARNING' ] && error_msg="$error_msg[$1] $2\n" } send_error_mail () { [ -z "$error_msg" ] && return echo -e "$error_msg" | mail -s "[WARNING]$BATCH_NAME report for `hostname`" -r crond warning write_log 'INFO' 'Send error mail' } start_delayed_job () { bin/delayed_job status > /dev/null 2>&1 if [ $? -eq 0 ]; then write_log 'INFO' "Running" return fi bin/delayed_job start > /dev/null 2>&1 if [ $? -ne 0 ]; then write_log 'ERROR' "Start failure: `pwd`/bin/delayed_job" else write_log 'WARNING' "Start success: `pwd`/bin/delayed_job" fi } write_log 'INFO' '=== START ===' start_delayed_job send_error_mail write_log 'INFO' '=== END ==='
mailコマンドのwarningは、aliasesで転送先のメールアドレスを設定しています。
これで安心して寝られますね。