SIGHUPとかで再起動するPerlスクリプトで、再起動後にシグナルが受信できない
現象
Perlでサーバとして動作するプログラムを作った時のこと。
SIGHUPとかのシグナルによって再起動させたいと思って安直に以下のように実装して、
$SIG{HUP} = sub { exec $0, @ARGV or die "Failed restart : $!"; };
SIGHUPを送ると再起動しました。
はい、OK〜っと思ったのですが、再度SIGHUPを送っても次からは再起動しないっす…。
POSIX::SigActionを使ってみる
Perlでシグナル処理について調べると、以下が見つかったので、
- perlipc - Perl のプロセス間通信 (シグナル, fifo, パイプ, 安全な副プロセス, ソケット, セマフォ) - perldoc.jp
- Perlでシグナル処理(DBIを黙らせる編) : D-7 <altijd in beweging>
参考にして以下のようにしてみたのですが、だめでした。
use POSIX (); my $sigset = POSIX::SigSet->new(&POSIX::SIGHUP); my $sigact = POSIX::SigAction->new(sub { exec $0, @ARGV or die "Failed restart : $!"; }, $sigset, &POSIX::SA_NODEFER); POSIX::sigaction(&POSIX::SIGHUP, $sigact);
local化してみる
local $SIG{HUP} = sub { exec $0, @ARGV or die "Failed restart : $!"; };
とか、以下を参考に、
use Sys::SigAction qw( set_sig_handler ); my $h = set_sig_handler('HUP', sub { exec $0, @ARGV or die "Failed restart : $!"; }, { flags => SA_NODEFER });
とかしてみましたが関係なし。
ようやくそれっぽい情報が
execを使用してプログラムを再起動すると、起動されたプロセスはブロックされたシグナルを継承するとのこと。
これかッ!と上記を参考にして、
use POSIX (); my $sigset = POSIX::SigSet->new(&POSIX::SIGHUP); my $sigact = POSIX::SigAction->new(sub { for my $nal ( qw{ ALRM CHLD HUP INT PIPE TERM } ) { $SIG{$nal} = sub {}; } my $s = POSIX::SigSet->new; my $t = POSIX::SigSet->new; POSIX::sigprocmask(&POSIX::SIG_BLOCK, $s, $t); exec $0, @ARGV or die "Failed restart : $!"; }, $sigset, &POSIX::SA_NODEFER); POSIX::sigaction(&POSIX::SIGHUP, $sigact);
としてみたのですが、やっぱりダメっす…。期待した分、テンション↓も大きい…。
シグナルのブロック解除で何か上手くいったっぽい
で、シグナルのブロックとかsigprocmaskとかSIG_BLOCKとか勉強した結果、
ブロック解除したいんだから、POSIX::SIG_UNBLOCKを使わないといけないんじゃないかと思い、
use POSIX (); my $sigset = POSIX::SigSet->new(&POSIX::SIGHUP); my $sigact = POSIX::SigAction->new(sub { exec $0, @ARGV or die "Failed restart : $!"; }, $sigset, &POSIX::SA_NODEFER); POSIX::sigprocmask(&POSIX::SIG_UNBLOCK, $sigset); POSIX::sigaction(&POSIX::SIGHUP, $sigact);
としたら、上手くいきました。
あとがき
でも、本当に良いのか自信無しです。ツッコミがあれば是非。
そもそもシグナルとかよくわかってないんだよなぁと。
似たような処理のサンプルを載せてるサイトは、たくさん見つかりましたが、
SIG_UNBLOCKを扱っている所は見つからなかったです。
これって初歩的な知識なんだろか。
それとも、Proc::Daemonとかのライブラリを使ってれば、意識する必要無いのかな。