美文网首页
pcntl信号机制配合swoole进程池 不影响业务平滑重启子进

pcntl信号机制配合swoole进程池 不影响业务平滑重启子进

作者: 骑蚂蚁上高速_jun | 来源:发表于2020-03-05 08:33 被阅读0次

    场景:
    由于公司的邮件Smtp服务器,是基于swoole的进程池实现的。但是swoole进程池,并没有平滑重启功能,如果当你的业务还在worker中运行的时候,通过 SIGUSR1 或 SIGUSR2 信号重新启动所有的worker,这样会导致你的部分业务丢失。

    解决方案:
    swoole进程池 的底层仅设置了主进程(管理进程)的信号处理,并未对 Worker 工作进程设置信号,如果你在worker中进行了
    信号监听,那么就可以实现worker 进程的平滑重启

    *   工作进程为异步模式,请使用 [Swoole\Process::signal](https://wiki.swoole.com/#/process?id=signal) 监听信号
    *   工作进程为同步模式,请使用 `pcntl_signal` 和 `pcntl_signal_dispatch` 监听信号
    
    由于swoole的进程池是同步模式,故采用 pcntl_signal
    $pool->on("WorkerStart", function (Pool $pool,int $workerId) {
        swoole_set_process_name("mail:pool:{$workerId}"); // 设置进程别名
        $redis = new Redis();
        $redis->connect("127.0.0.1");
        $redis->setOption(Redis::OPT_READ_TIMEOUT,-1);
        $run=true;
    
    /**
    * 安装信号,便于调用
    * 不会主动执行,由信号触发器 触发执行
    * 发送 USR1 信号 会重启进程
    * 发送 TERM 信号 会停止信号
    */
        pcntl_signal(SIGTERM, function ($signo) use(&$run,$pool){
            echo "pcntl收到 {$signo} 信号\n";
            $run=false;
        });
        echo "进入redis->{$workerId}\n";
        while($run){
            if($redis->ping() != "+PONG"){
                $redis = new redis;
                $redis->connect("127.0.0.1");
                $redis->setOption(redis::OPT_READ_TIMEOUT,-1);
            }
    
            $data = $redis->brPop("list:swoole",3);
    /***
    * 等待外部信号,并且调用信号。该函数有两个功能。
    1 . 等待外部信号调用。2.触发信号。
    备注: 该函数只有接收到外部信号时,才能触发信号
    */
            pcntl_signal_dispatch();
            $datas = $data[1] ?? "";
            if($datas){
                require "/data/wwwroot/php-cli/beanstalk.php";
                co::sleep(20); // 代替业务逻辑等待
                $log= "写入数据内容 : {$datas}\n";
                echo $log;
                file_put_contents("/data/wwwroot/php-cli/swoole.log",$log,FILE_APPEND);
            }
    
        }
    });
    
    

    守护进程启动程序,及检测启动工作进程是否正常

    $ php test -d=true  # 守护进程启动
    $ ps -ef | grep php  # 查看主进程是否启动运行 如果在运行可看到主进程号  Pid
                                  # ps -ef | grep pool   通过进程别名可以看到更详细的信息
    $ pstree -p Pid # 查看进程树 得到子进程的数量是否与进程池设定的数量是否相等,相等则表示正常          
    

    平滑重启动和停止

    $ kill -USR1 Pid # 重启
    $ kill -TERM Pid # 停止
    

    相关文章

      网友评论

          本文标题:pcntl信号机制配合swoole进程池 不影响业务平滑重启子进

          本文链接:https://www.haomeiwen.com/subject/enazlhtx.html