1、 進程守護使用場景。php
後端常常會有相似這樣的場景,某個腳本,須要不斷的重複運行,這個時候,最好有一python
個守護程序,幫助咱們不斷地自動地拉起這些腳本進程,讓它自動地重複運行。後端
在 Linux/Unix 系統下,supervisor 就是使用 python 開發的一個優秀的進程管理工swoole
具,本文嘗試使用 php 來實現相似的進程管理工具。工具
2、swoole 的進程管理模塊。this
php 的 swoole 擴展有一個進程管理模塊,官方文檔見:swoole 進程管理模塊spa
參考 supervisor 的實現方式,被守護的進程是做爲 supervisor 的子進程來啓動的,進程
supervisor 經過監聽子進程的信號,可實現對子進程的自動重啓等功能。而 swooleip
的進程管理模塊就提供了進程間通訊的功能,能夠實現對子進程的自動重啓功能。資源
3、第一個進程守護程序。
要實現對子程序的守護,須要作到兩點:
1. 程序須要監聽到子進程的結束信號,以便於從新拉起新的子進程。
2. 子進程的運行環境須要獨立於父進程。swoole 進程管理模塊提供了一個 bool Process->exec(string $execfile, array
$args) 方法,讓子進程蛻變成另外一個系統調用程序,同時還能保證父進程與當前進程
仍然是父子進程關係。
再經過 array Process::wait(bool $blocking = true) 方法,來等待子進程的退出信號。
下面是使用 swoole 啓動子進程,並回收子進程資源的示例代碼:
<?phpuse Swoole\Process;
$php = "/usr/bin/env php";
$script = dirname(__DIR__) . "/task.php";
$command = "{$php} {$script}";
$process = new Process(function (Process $worker) use ($command) {
$worker->exec('/bin/sh', ['-c', $command]);
});
$pid = $process->start();
printf("啓動子進程 {$pid}\n");
while ($ret = Process::wait()) {
$pid = intval($ret["pid"] ?? 0);
printf("子進程 {$pid} 結束\n");}
代碼解析:
$command 變量表示須要子進程腳本,經過 exec() 方法來啓動成一個子進程的方式
運行,再經過 Process::wait() 訪求來等待 $command 這個子進程腳本結束,並回收
進程資源。
那麼,只要在收到子進程的結束信號後,再起一個相同的子進程腳本,便可實現對子進
程的守護了。因而,第一個守護子進程的程序實現代碼:
<?phpuse Swoole\Process;
$php = "/usr/bin/env php";
$script = dirname(__DIR__) . "/task.php";
$command = "{$php} {$script}";
do {
$process = new Process(function (Process $worker) use ($command) {
$worker->exec('/bin/sh', ['-c', $command]);
});
$pid = $process->start();
printf("啓動子進程 {$pid}\n");
} while (Process::wait());代碼解析:
這段代碼只將啓動子進程的邏輯加到一個死循環中,好讓這個子進程腳本可以不斷的重
啓。
4、封裝成類
爲了方便重用這段代碼,能夠將這段代碼封裝成一個簡單的類:
<?phpnamespace App;
use Swoole\Process;
class Daemon{
/** @var string */
private $command;
public function __construct(string $command)
{
$this->command = $command;
}
public function run()
{
do {
$process = new Process(function (Process $worker) {
$worker->exec('/bin/sh', ['-c', $this->command]); });
$pid = $process->start();
} while (Process::wait());
}
}
那麼,這個 Daemon 類的使用方式以下:
<?php
use App\Daemon;
$php = "/usr/bin/env php";
$script = dirname(__DIR__) . "/task.php";
$command = "{$php} {$script}";
$daemon = new Daemon($command);
$daemon->run();
這個簡單 Daemon 類雖然能實現對單個腳本進行重啓守護,可是,若是咱們有許多個
腳本同時須要守護的,這個 Daemon 類顯然是不可以知足需求的。