进程

用途

处理耗时任务,比如循环处理队列消息,清除多余redis中的token数据等等。

例子

定义一个进程类

use EasySwoole\Component\Process\AbstractProcess;

class Process extends AbstractProcess
{

    protected function run($arg)
    {
        //当进程启动后,会执行的回调
        var_dump($this->getProcessName()." run");
        var_dump($arg);
    }

    protected function onPipeReadable(\Swoole\Process $process)
    {
        /*
         * 该回调可选
         * 当有主进程对子进程发送消息的时候,会触发的回调,触发后,务必使用
         * $process->read()来读取消息
         */
    }

    protected function onShutDown()
    {
        /*
         * 该回调可选
         * 当该进程退出的时候,会执行该回调
         */
    }

    protected function onException(\Throwable $throwable, ...$args)
    {
        /*
         * 该回调可选
         * 当该进程出现异常的时候,会执行该回调
         */
    }
}

注册进程

我们在EasySwoole全局的 mainServerCreate 事件中进行进程注册

use App\Process;
use EasySwoole\Component\Process\Config;

$processConfig = new Config();
$processConfig->setProcessName('testProcess');
/*
 * 传递给进程的参数
*/
$processConfig->setArg([
    'arg1'=>time()
]);
ServerManager::getInstance()->getSwooleServer()->addProcess((new Process($processConfig))->getProcess());
注意,一个进程模型可以被注册N次,也就是创建N个相同类型的进程

自定义进程热重启

在Swoole 文档中,明确提及自定义进程无法像worker一样reload 。但想实现,终归有办法的,我们只要知道某个进程的pid,给他发送SIGTERM命令, 这个进程自己就会推出。而再利用Swoole Manager会重新拉起进程的这个特性,绕一圈实现进程的热重启。

实例代码

namespace App\HttpController;

use EasySwoole\Http\AbstractInterface\Controller;

class Index extends Controller
{

    function index()
    {
        $pid = $this->request()->getRequestParam('pid');
        \Swoole\Process::kill($pid,SIGTERM);
        $this->writeJson(200,null,'send reboot signal');
    }
}

定义一个控制器,用来发送信号,当然,这个逻辑可有其他方式

namespace App\ProcessReload;

use EasySwoole\Component\Timer;
use EasySwoole\EasySwoole\Logger;

class Work
{
    static function run()
    {
        Timer::getInstance()->loop(3000,function (){
            $pid = getmypid();
            Logger::getInstance()->info("asassdaasd");
        });
    }
}

定义一个任务类,注意,run方法为静态

namespace App\ProcessReload;

use EasySwoole\Component\Process\AbstractProcess;
use EasySwoole\EasySwoole\Logger;

class Process extends AbstractProcess
{

    protected function run($arg)
    {
        $pid = getmypid();
        Logger::getInstance()->info("process for pid {$pid} start");
        Work::run();
    }

    function onShutDown()
    {
        $pid = getmypid();
        Logger::getInstance()->info("process for pid {$pid} shutdown");
        parent::onShutDown();
    }
}

定义一个进程类,进程类的run方法静态调用任务类的静态方法即可。

原理讲解

这里面主要的问题,在于自定义进程类还需要再去调用一个任务类。很多人可能不解。实际上的原理是因为, 我要注册一个进程的时候,我需要new一个自定义进程类,因此,自定义进程的代码就在主进程中被require进去,因此以后续无论如何再怎么修改, manager进程重新克隆出来的进程还是之前的代码。而这里面就巧妙的利用了、当我new这个类的时候,因为php是解释性语言,run方法并未立即被执行。 只有当我真的发生进程克隆的时候,也就是process start后,才会真正的去执行run()这个方法, 而我进程类run方法里面的内容,当执行到Work::run()的时候,才会真正的去加载worker类的代码,因此我每次杀掉这个自定义进程的时候,进程 重新被主进程克隆出来的时候,都会重新去加载Work类的代码。

Pid管理

很多方式,可以自己用swoole table或者是redis,文件等多种方式实现。