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で転送先のメールアドレスを設定しています。
これで安心して寝られますね。
