[PHP]execでバックグラウンド実行するときの落とし穴に落ちた。 nohup!nohup!
logrotateでコマンドが中断されてしまうメカニズム
そのサーバではcronの設定が下記のようになっており、/etc/crontab
27 0 * * * root run-parts /etc/cron.daily
毎日0:27 に/etc/cron.daily/*が呼び出される設定になっていました。そこには/etc/cron.daily/loglotateという実行コマンドがあります。
そしてlogrotateの設定はというと、
/etc/logrotate.d/httpd
/var/log/httpd/*log {
daily
rotate 30
compress
missingok
notifempty
sharedscripts
postrotate
/sbin/service httpd reload > /dev/null 2>/dev/null || true
endscript
}
となっておりました。service httpd reloadはどうなっているのかというと、
service httpd の実体は /etc/init.d/httpd なのでそれを見てみます。
/etc/init.d/httpd
reload() {
echo -n $"Reloading $prog: "
if ! LANG=$HTTPD_LANG $httpd $OPTIONS -t >&/dev/null; then
RETVAL=$?
echo $"not reloading due to configuration syntax error"
failure $"not reloading $httpd due to configuration syntax error"
else
killproc -p ${pidfile} $httpd -HUP;
RETVAL=$?
fi
echo
}
このようにApacheに対してHUPシグナルが送られます。ApacheにHUPシグナルを送るとどうなるのかというと、
"停止と再起動 - Apache HTTP サーバ"子プロセスをkillしてしまうようです。(ここでkillと言ってるのはHUPシグナルのことでしょうか?)
HUP あるいは restart シグナルを親プロセスに送ると、 TERM と同様に子プロセスを kill しますが、 親プロセスは終了しません。 設定ファイルを再読込して、ログファイル全てを開き直します。 その後、新しい子プロセスを起動して応答を続けます
要約すると、「execで外部コマンドをバックグランドで走らせてる間にlogrotateが実行されると、外部コマンドが強制終了してしまう」ということです。
何とも
回避方法
コマンド実行の際に、頭に'nohup'を付ける。# バックグランドでcommandを実行
exec('command > /dev/null &');
↓
exec('nohup command > /dev/null &');
または、logrotateの処理をreloadではなくgracefulにする。
/sbin/service httpd reload
↓
/sbin/service httpd graceful
私が実験してみたところ、どちらか片方だけでも回避できましたが、両方やっておくのが安全だと思います。