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