自定義進(jìn)程
PHP
自帶的pcntl
存在許多不足,不支持重定向標(biāo)準(zhǔn)輸入和輸出及進(jìn)程間通信的功能,且容易使用錯(cuò)誤。
EasySwoole
基于Swoole
的Process
模塊進(jìn)行了封裝,來(lái)創(chuàng)建工作進(jìn)程,用于處理耗時(shí)任務(wù),消息隊(duì)列,等其它的特殊任務(wù)。
在EasySwoole
啟動(dòng)時(shí),會(huì)自動(dòng)創(chuàng)建注冊(cè)的進(jìn)程,并執(zhí)行進(jìn)程指定的邏輯代碼,進(jìn)程意外退出時(shí),會(huì)被重新拉起。
創(chuàng)建一個(gè)自定義進(jìn)程
需要定義一個(gè)進(jìn)程類繼承EasySwoole\Component\Process\AbstractProcess
。
定義進(jìn)程內(nèi)執(zhí)行邏輯回調(diào)
protected function run($arg)
{
// TODO: Implement run() method.
$this->getProcessName(); // 獲取注冊(cè)進(jìn)程名稱
$this->getProcess(); // 獲取進(jìn)程實(shí)例 \Swoole\Process
$this->getPid(); // 獲取當(dāng)前進(jìn)程Pid
$this->getArg(); // 獲取注冊(cè)時(shí)傳遞的參數(shù)
}
進(jìn)程間通信Pipe回調(diào)
protected function onPipeReadable(Process $process)
{
// 該回調(diào)可選
// 當(dāng)主進(jìn)程對(duì)子進(jìn)程發(fā)送消息的時(shí)候 會(huì)觸發(fā)
$process->read(); // 讀取消息
}
進(jìn)程間異?;卣{(diào)
protected function onException(\Throwable $throwable, ...$args)
{
// 該回調(diào)可選
// 捕獲run方法內(nèi)拋出的異常
// 這里可以通過(guò)記錄異常信息來(lái)幫助更加方便的知道出現(xiàn)問(wèn)題的代碼
}
進(jìn)程信號(hào)回調(diào)
protected function onSigTerm()
{
// 當(dāng)進(jìn)程接收到 SIGTERM 信號(hào)觸發(fā)該回調(diào)
}
進(jìn)程意外退出回調(diào)
protected function onShutDown()
{
// 該回調(diào)可選
// 進(jìn)程意外退出 觸發(fā)此回調(diào)
// 大部分用于清理工作
}
注冊(cè)進(jìn)程
在 EasySwoole
全局的 mainServerCreate
事件中進(jìn)行進(jìn)程注冊(cè)
$processConfig = new \EasySwoole\Component\Process\Config([
'processName' => 'CustomProcess', // 設(shè)置 自定義進(jìn)程名稱
'processGroup' => 'Custom', // 設(shè)置 自定義進(jìn)程組名稱
'arg' => [
'arg1' => 'this is arg1!'
], // 【可選參數(shù)】設(shè)置 注冊(cè)進(jìn)程時(shí)要傳遞給自定義進(jìn)程的參數(shù),可在自定義進(jìn)程中通過(guò) $this->getArg() 進(jìn)行獲取
'enableCoroutine' => true, // 設(shè)置 自定義進(jìn)程自動(dòng)開(kāi)啟協(xié)程
]);
\EasySwoole\Component\Process\Manager::getInstance()->addProcess(new CustomProcess($processConfig));
推薦使用 \EasySwoole\Component\Process\Manager
類進(jìn)行注冊(cè)自定義進(jìn)程,注冊(cè)方式示例代碼如上所示。如果您的框架版本過(guò)低,不支持 \EasySwoole\Component\Process\Manager
類,可使用如下方式進(jìn)行注冊(cè)自定義進(jìn)程: \EasySwoole\EasySwoole\ServerManager::getInstance()->getSwooleServer()->addProcess((new TickProcessnew CustomProcess($processConfig));
注意:用戶在注冊(cè)多個(gè)相同配置的自定義進(jìn)程時(shí),請(qǐng)一定不要復(fù)用實(shí)例化后的進(jìn)程對(duì)象,而應(yīng)該重新實(shí)例化一個(gè)新的進(jìn)程對(duì)象。如果復(fù)用了將導(dǎo)致不可預(yù)知的結(jié)果。正確注冊(cè)和錯(cuò)誤注冊(cè)的參考示例代碼如下:
錯(cuò)誤的注冊(cè)示例:
EasySwooleEvent.php
:
<?php
namespace EasySwoole\EasySwoole;
use EasySwoole\EasySwoole\AbstractInterface\Event;
use EasySwoole\EasySwoole\Swoole\EventRegister;
class EasySwooleEvent implements Event
{
public static function initialize()
{
date_default_timezone_set('Asia/Shanghai');
}
public static function mainServerCreate(EventRegister $register)
{
$processConfig = new \EasySwoole\Component\Process\Config([
'processName' => 'TestProcess', // 設(shè)置 進(jìn)程名稱為 TickProcess
]);
// 【推薦】使用 \EasySwoole\Component\Process\Manager 類注冊(cè)自定義進(jìn)程
$testProcess = new \App\Process\TestProcess($processConfig);
### !!! 錯(cuò)誤原因:把上述實(shí)例化得到的自定義進(jìn)程對(duì)象 $testProcess 進(jìn)行了復(fù)用,注冊(cè)了 2 次,將導(dǎo)致未知錯(cuò)誤。
// 注冊(cè)進(jìn)程
\EasySwoole\Component\Process\Manager::getInstance()->addProcess($testProcess);
\EasySwoole\Component\Process\Manager::getInstance()->addProcess($testProcess);
}
}
正確的注冊(cè)示例:
EasySwooleEvent.php
:
<?php
namespace EasySwoole\EasySwoole;
use EasySwoole\EasySwoole\AbstractInterface\Event;
use EasySwoole\EasySwoole\Swoole\EventRegister;
class EasySwooleEvent implements Event
{
public static function initialize()
{
date_default_timezone_set('Asia/Shanghai');
}
public static function mainServerCreate(EventRegister $register)
{
$processConfig = new \EasySwoole\Component\Process\Config([
'processName' => 'TestProcess', // 設(shè)置 進(jìn)程名稱為 TickProcess
]);
// 【推薦】使用 \EasySwoole\Component\Process\Manager 類注冊(cè)自定義進(jìn)程
$testProcess1 = new \App\Process\TestProcess($processConfig);
$testProcess2 = new \App\Process\TestProcess($processConfig);
### 正確的注冊(cè)進(jìn)程的示例:重新使用 new 實(shí)例化另外 1 個(gè)新的自定義進(jìn)程對(duì)象,然后進(jìn)行注冊(cè)
// 注冊(cè)進(jìn)程
\EasySwoole\Component\Process\Manager::getInstance()->addProcess($testProcess1);
\EasySwoole\Component\Process\Manager::getInstance()->addProcess($testProcess2);
}
}
上文的 \App\Process\TestProcess
和下文的 \App\Process\CustomProcess
類的代碼類似,這里不做重復(fù)說(shuō)明。
完整示例代碼
1. 定義自定義進(jìn)程類示例
首先,我們定義一個(gè)自定義進(jìn)程類繼承 \EasySwoole\Component\Process\AbstractProcess
類,示例代碼如下:
<?php
namespace App\Process;
use EasySwoole\Component\Process\AbstractProcess;
use Swoole\Process;
class CustomProcess extends AbstractProcess
{
protected function run($arg)
{
// TODO: Implement run() method.
$processName = $this->getProcessName(); // 獲取 注冊(cè)進(jìn)程名稱
$swooleProcess = $this->getProcess(); // 獲取 注冊(cè)進(jìn)程的實(shí)例 \Swoole\Process
$processPid = $this->getPid(); // 獲取 當(dāng)前進(jìn)程 Pid
$args = $this->getArg(); // 獲取 注冊(cè)進(jìn)程時(shí)傳遞的參數(shù)
var_dump('### 開(kāi)始運(yùn)行自定義進(jìn)程 start ###');
var_dump($processName, $swooleProcess, $processPid, $args);
var_dump('### 運(yùn)行自定義進(jìn)程結(jié)束 end ###');
}
protected function onPipeReadable(Process $process)
{
// 該回調(diào)可選
// 當(dāng)主進(jìn)程對(duì)子進(jìn)程發(fā)送消息的時(shí)候 會(huì)觸發(fā)
$recvMsgFromMain = $process->read(); // 用于獲取主進(jìn)程給當(dāng)前進(jìn)程發(fā)送的消息
var_dump('收到主進(jìn)程發(fā)送的消息: ');
var_dump($recvMsgFromMain);
}
protected function onException(\Throwable $throwable, ...$args)
{
// 該回調(diào)可選
// 捕獲 run 方法內(nèi)拋出的異常
// 這里可以通過(guò)記錄異常信息來(lái)幫助更加方便地知道出現(xiàn)問(wèn)題的代碼
}
protected function onShutDown()
{
// 該回調(diào)可選
// 進(jìn)程意外退出 觸發(fā)此回調(diào)
// 大部分用于清理工作
}
protected function onSigTerm()
{
// 當(dāng)進(jìn)程接收到 SIGTERM 信號(hào)觸發(fā)該回調(diào)
}
}
2. 注冊(cè)進(jìn)程示例
然后在 mainServerCreate
事件中進(jìn)行注冊(cè)進(jìn)程,示例代碼如下:
<?php
namespace EasySwoole\EasySwoole;
use EasySwoole\EasySwoole\AbstractInterface\Event;
use EasySwoole\EasySwoole\Swoole\EventRegister;
class EasySwooleEvent implements Event
{
public static function initialize()
{
date_default_timezone_set('Asia/Shanghai');
}
public static function mainServerCreate(EventRegister $register)
{
$processConfig = new \EasySwoole\Component\Process\Config([
'processName' => 'CustomProcess', // 設(shè)置 進(jìn)程名稱為 TickProcess
'processGroup' => 'Custom', // 設(shè)置 進(jìn)程組名稱為 Tick
'arg' => [
'arg1' => 'this is arg1!',
], // 傳遞參數(shù)到自定義進(jìn)程中
'enableCoroutine' => true, // 設(shè)置 自定義進(jìn)程自動(dòng)開(kāi)啟協(xié)程環(huán)境
]);
// 【推薦】使用 \EasySwoole\Component\Process\Manager 類注冊(cè)自定義進(jìn)程
$customProcess = (new \App\Process\CustomProcess($processConfig));
// 【可選操作】把 tickProcess 的 Swoole\Process 注入到 Di 中,方便在后續(xù)控制器等業(yè)務(wù)中給自定義進(jìn)程傳輸信息(即實(shí)現(xiàn)主進(jìn)程與自定義進(jìn)程間通信)
\EasySwoole\Component\Di::getInstance()->set('customSwooleProcess', $customProcess->getProcess());
// 注冊(cè)進(jìn)程
\EasySwoole\Component\Process\Manager::getInstance()->addProcess($customProcess);
/*
#【針對(duì)于低版本不支持 \EasySwoole\Component\Process\Manager 類】可使用 \EasySwoole\EasySwoole\ServerManager 類注冊(cè)自定義進(jìn)程
$customProcess = (new \App\Process\CustomProcess($processConfig))->getProcess();
// 【可選操作】把 tickProcess 的 Swoole\Process 注入到 Di 中,方便在后續(xù)控制器等業(yè)務(wù)中給自定義進(jìn)程傳輸信息(即實(shí)現(xiàn)主進(jìn)程與自定義進(jìn)程間通信)
\EasySwoole\Component\Di::getInstance()->set('customSwooleProcess', $customProcess);
// 注冊(cè)進(jìn)程
\EasySwoole\EasySwoole\ServerManager::getInstance()->getSwooleServer()->addProcess($customProcess);
*/
}
}
3. 向自定義進(jìn)程中傳遞消息
<?php
namespace App\HttpController;
use EasySwoole\Component\Di;
use EasySwoole\Http\AbstractInterface\Controller;
class Index extends Controller
{
public function index()
{
// 獲取 Di 中注入的 自定義進(jìn)程
$customProcess = Di::getInstance()->get('customSwooleProcess');
// 向自定義進(jìn)程中傳輸信息,會(huì)觸發(fā)自定義進(jìn)程的 onPipeReadable 回調(diào)
$customProcess->write('this is test!');
}
}
進(jìn)程管理命令說(shuō)明
EasySwoole
內(nèi)置了對(duì)于 Process
的命令行操作,方便開(kāi)發(fā)者非常友好地去管理 Process
。
可執(zhí)行 php easyswoole.php process -h
來(lái)查看具體操作。
顯示所有進(jìn)程
php easyswoole.php process show
如果想要以 MB
形式顯示:
php easyswoole.php process show -d
殺死指定進(jìn)程(PID)
php easyswoole.php process kill --pid=PID
殺死指定進(jìn)程組(GROUP)
php easyswoole.php process kill --group=GROUP_NAME
殺死所有進(jìn)程
php easyswoole.php process killAll
強(qiáng)制殺死進(jìn)程
需要帶上 -f
參數(shù),例如:
php easyswoole.php process kill --pid=PID -f