LoginSignup
5

More than 5 years have passed since last update.

PHP だけで HUP シグナルを受けてリスタートする

Posted at

例えば 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 でリスタートするたびにファイルディスクリプタが増えていきます。

さいごに

たぶん役に立たない。

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
What you can do with signing up
5