例えば PHP でバックグラウンドな処理のために常駐するデーモン的なもの作ったとき、アプリを更新したときはプロセスをリスタートする必要があります。
普通は systemd とかでデーモンにして systemctl restart ore-no-app
とかで良いのだけれども、あえて PHP 単体で HUP シグナルでリスタート出来るようにする方法。
<?php
$term = false;
$restart = false;
foreach ([SIGHUP, SIGINT, SIGTERM] as $sig) {
pcntl_signal($sig,function ($signo) {
global $term;
global $restart;
$term = true;
if ($signo === SIGHUP) {
$restart = true;
}
});
}
$pid = getmypid();
echo "\nstart [$pid]\n";
// $socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
while ($term == false) {
echo ".";
sleep(1);
pcntl_signal_dispatch();
}
if ($restart) {
echo "\nrestart [$pid]\n";
$exe = readlink("/proc/$pid/exe");
$cmdline = file_get_contents("/proc/$pid/cmdline");
$args = explode("\0", rtrim($cmdline, "\0"));
pcntl_exec($exe, array_splice($args, 1));
} else {
echo "\nstop [$pid]\n";
}
このスクリプトを実行すると、
php sample.php
次のように出力されます。
start [6394]
...............
おもむろにスクリプトを修正しても、
- echo ".";
+ echo "x";
それだけでは何も変わりません。
start [6394]
....................
HUP をぶっ刺すと、
kill -HUP 6394
反映される。
start [6394]
.........................
restart [6394]
start [6394]
xxxxxxxxxxxxxx
注意
要するに exec で自分自分を再実行しています。exec で pid を変えずにプロセスの置き換えができる POSIX ならではの方法。
ただし、元のプロセスからファイルディスクリプタを引き継いでしまうので、なにかしらのファイルディスクリプタを開いたままで exec するとリークします。
例えば↑のスクリプトで下記のようにソケットの作成をコメントインすると・・・
-// $socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
+$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
HUP でリスタートするたびにファイルディスクリプタが増えていきます。
さいごに
たぶん役に立たない。