SWOOLEを使用してプロセスのデーモンを実現する(二)

5801 ワード

前の記事「swooleを使用してプロセスを実装するデーモン(一)」では、サブプロセスを自動的に再起動できるデーモンクラスが初歩的に実装されています.しかし、このデーモンクラスには、単一のサブプロセスのみをサポートするデーモンクラスが明らかな欠点があります.
一、複数のスクリプトを守るプログラムをサポートする
実際には、通常、複数のサブプロセスを保護する必要があります.このDaemonを拡張するのも簡単です.コンストラクション関数のパラメータをstringからarrayに変更するだけです.複数のスクリプトを保護するDaemonクラスをサポートし、次のように書き換えます.
use Swoole\Process;

class Daemon
{
    /**
     * @var string[]
     */
    private $commands;

    /**
     * @var array
     */
    private $workers = [];


    public function __construct(array $commands)
    {
        $this->commands = $commands;
    }

    public function run()
    {
        foreach ($this->commands as $index => $command) {
            $pid = $this->createWorker($command);
            $this->workers[$pid] = $command;
        }
        $this->waitAndRestart();
    }

    private function waitAndRestart()
    {
        while (1) {
            if ($ret = Process::wait(false)) {
                $retPid = intval($ret["pid"] ?? 0);

                if (isset($this->workers[$retPid])) {

                    $command = $this->workers[$retPid];
                    $newPid = $this->createWorker($command);

                    $this->workers[$newPid] = $command;
                    unset($this->workers[$retPid]);
                }
            }
        }
    }

    /**
     *      ,       id
     * @param $command
     * @return int
     */
    private function createWorker($command): int
    {
        $process = new Process(function (Process $worker) use ($command) {
            $worker->exec('/bin/sh', ['-c', $command]);
        });
        return $process->start();
    }

}

コード解析:run()メソッドを実行すると、各サブプロセスが作成され、waitAndRestart()を使用して待機し、実行が終了したサブプロセスがあれば新しいサブプロセスが再開されます.
この新しいDaemonクラスの使用方法は、次のようになります.
$php = "/usr/bin/env php";
$script1 = dirname(__DIR__) . "/task1.php";
$script2 = dirname(__DIR__) . "/task2.php";

$commands = [
    "{$php} {$script1}",
    "{$php} {$script2}",
];

$daemon = new Daemon($commands);
$daemon->run();

しかし、このような使い方は、やはり便利ではありません.結局、守るべきプログラムを追加または減らすには、以上のコードを変更し、supervisorを参照して、プロファイルを使用して、守るべきプログラムを動的に修正することをサポートすることができます.
二、使用プロファイルのサポート
PHPには内蔵の関数parse_があります.ini_file()は解析可能である.ini接尾辞のプロファイルは、便宜上、使用可能である.iniファイルを構成として使用します.
まず、プログラムの構成フォーマットを定義します.
[task-1]
command = "/usr/bin/env php /var/www/html/task/task1.php"

idがtask-1であるプログラムを保護することを示し、その実行コマンドは/usr/bin/env php/var/www/html/task/task 1である.php
この構成を表すCommandクラスを定義します.
class Command
{
    /**
     *      id
     * @var string
     */
    private $id;

    /**
     *       command   
     * @var string
     */
    private $command;

    // ...          get set    ...

}

同様に、Daemonクラスのコンストラクション関数パラメータをプロファイルパスに変更するだけで、プロファイルをサポートするDaemonクラスは、次のように書き換えられます.
use Swoole\Process;

class Daemon
{
    /**
     * @var string
     */
    private $configPath;

    /**
     * @var Command[]
     */
    private $commands;

    /**
     * @var array
     */
    private $workers = [];

    public function __construct(string $configPath)
    {
        $this->configPath = $configPath;
    }


    public function  run()
    {
        $this->parseConfig();
        foreach ($this->commands as $command) {
            $pid = $this->createWorker($command->getCommand());
            $this->workers[$pid] = $command->getCommand();

        }
        $this->waitAndRestart();
    }

    /**
     *        
     */
    private function waitAndRestart()
    {
        while (1) {
            if ($ret = Process::wait(false)) {
                $retPid = intval($ret["pid"] ?? 0);

                if (isset($this->workers[$retPid])) {

                    $commandLine = $this->workers[$retPid];
                    $newPid = $this->createWorker($commandLine);

                    $this->workers[$newPid] = $commandLine;
                    unset($this->workers[$retPid]);
                }
            }
        }
    }


    /**
     *       
     */
    private function parseConfig()
    {
        if (is_readable($this->configPath)) {
            $iniConfig = parse_ini_file($this->configPath, true);

            $this->commands = [];
            foreach ($iniConfig as $id => $item) {
                $commandLine = strval($item["command"] ?? "");

                $command = new Command();
                $command->setId($id);
                $command->setCommand($commandLine);
                $this->commands[] = $command;
            }
        }
    }

    /**
     *      ,       id
     * @param $command
     * @return int
     */
    private function createWorker($command): int
    {
        $process = new Process(function (Process $worker) use ($command) {
            $worker->exec('/bin/sh', ['-c', $command]);
        });
        return $process->start();
    }

}

コード解析:主な変更点は、プロファイルの内容を読み取る機能を完了するためにparseConfig()メソッドを追加することです.
プロファイルを作成するiniの内容は以下の通りです.
[task-1]
command = "/usr/bin/env php /var/www/html/task/task1.php"

[task-2]
command = "/usr/bin/env php /var/www/html/task/task2.php"

最終的に、このDaemonクラスの使用方法は、次のようになります.
$configPath = dirname(__DIR__) . "/config/daemon.ini";

$daemonMany = new Daemon($configPath);
$daemonMany->run();

三、終わり
これまで、このDaemonクラスは比較的柔軟だったと言えますが、まだ不足している点があります.例えば、これは常駐プロセスなので、プロファイルを変更したら、プロファイルを有効にするには、親プロセスを再起動する必要があります.親プロセスを再起動しないで、プロファイルを有効にする方法はありませんか.
次の記事では、swoole実装プロセスのデーモン(3)を使用して、プロセスの信号とswooleのコラボレーションを組み合わせて、このDaemonクラスを拡張し続けます.