大肠猴 2021-11-24 00:10 采纳率: 0%
浏览 16
已结题

php swoole 新版本移除了自动event::wait()后如何让进程监听文件修改状态的同时监听信号以及子进程的异常退出

问题遇到的现象和发生背景

在学习swoole的过程中,使用了目前最新的swoole 4.8.2,在使用swoole_event_add的时候,没有加入 Swoole\Event::wait(),导致监听无效,如果在swoole_event_add之后加上Swoole\Event::wait(),那么整个程序就阻塞在Swoole\Event::wait(),之后的代码就不再运行。
现在是使用swoole_event_add来监听文件变化,然后用pcntl_wait($status)阻塞读取子进程状态,还使用了pcntl_signal来绑定了接收到信号后的处理(重启子进程或者是关闭所有进程)。
最主要的问题事如何让swoole_event_add生效?
使用register_shutdown_function注册Swoole\Event::wait()也没用

问题相关代码,请勿粘贴截图
<?php
class Worker{
    //监听socket
    protected $socket = NULL;
    //连接事件回调
    public $onConnect = NULL;
    public  $reusePort=1;
    //接收消息事件回调
    public $onMessage = NULL;
    public $workerNum=1; //子进程个数
    public  $allSocket; //存放所有socket
    public  $addr;
    protected $worker_pid; //子进程pid
    protected  $master_pid;//主进程id
    protected $watch_fd;//文件监视的句柄
    public function __construct($socket_address) {
        //监听地址+端口
        $this->addr=$socket_address;
        $this->master_pid=posix_getpid();
    }
    public function start() {
//        register_shutdown_function(function () {
//            Swoole\Event::wait();
//        });

        //获取配置文件
        $test=include 'index.php';
        $this->watch();//文件监视,发生改变之后发送信号
        echo 'fork'.PHP_EOL;
        $this->fork($this->workerNum);
        echo 'start'.PHP_EOL;
        $this->monitorWorkers(); //监视程序,捕获信号,监视worker进程
        echo 'wait'.PHP_EOL;
        Swoole\Event::wait();
    }

    /**
     * 文件监视,自动重启
     */
        $files=get_included_files();//引入的所有文件
        foreach ($files as $file){
            inotify_add_watch($init,$file,IN_MODIFY); //监视相关的文件,IN_MODIFU 修改状态
//        stream_set_blocking($init,0);
//
//        while (1){
//            $events=inotify_read($init);//读取修改的信息
//            if(!empty($events)){//发生了改动
//                var_dump($events);
//            if(!empty($events)){//发生了改动
//                var_dump($events);
//            }
//        }
        //监听
            if(!empty($events)){//发生了改动
                echo posix_getpid().'的'.(int)$fd.'文件发生了变化'.PHP_EOL;
                posix_kill($this->master_pid,SIGUSR1);//发送信号
    }
    /**
     */
    public  function monitorWorkers(){
        echo 'works'.PHP_EOL;

        pcntl_signal(SIGUSR1, array($this, 'signalHandler'),false); //重启woker进程信号
        //ctrl+c
        pcntl_signal(SIGINT, array($this, 'signalHandler'),false); //杀死woker进程信号
        echo 'wwwww';
            $status=0;

            while (1){
                // 当发现信号队列,一旦发现有信号就会触发进程绑定事件回调
                pcntl_signal_dispatch();//接受信号触发事件
                echo '得到信号钱';
                pcntl_wait($status)
                //如果进程不是正常情况下的退出,重启子进程,我想要维持子进程个数
                var_dump($pid,$status);
                echo '得到信号后';
                $index=array_search($pid,$this->worker_pid);
                    $index=array_search($pid,$this->worker_pid);
                    $this->fork(1);
                    var_dump('拉起子进程');
                    unset($this->worker_pid[$index]);
                }
               echo '执行1';
              pcntl_signal_dispatch();//这里时担心在重启的过程中又接收到其他信号
            }

    }
    public function signalHandler($sigo){
            var_dump($sigo);          
            case SIGUSR1://接受到的信号
                $this->reload();
                echo "收到重启信号";
                break;
            case SIGINT:
                $this->stopAll();
                echo "按下ctrl+c,关闭所有字进程";
                swoole_event_del($this->watch_fd);
                exit(); break;
        }

    }
    public function fork($worker_num){
        for ($i=0;$i<$worker_num;$i++){

//            $test=include 'index.php';//这里是父进程引入文件,应该会多次引入,没用测试
//            var_dump($test);exit;
                exit('创建失败');
            }else if($pid>0){
                //父进程空间,返回子进程id
                while (true){
                    echo posix_getpid().PHP_EOL;
                    sleep(5);
            }
        }
        echo  '333'.PHP_EOL;;
//        exit;//这里如果exit,主进程就会退出来,导致下面结束子进程的代码失效
//        echo '1';
    }
   

    /**
     * 重启worker进程
     */
    public  function reload(){

        foreach ($this->worker_pid as $index=>$pid){
            posix_kill($pid,SIGKILL); //结束进程
            var_dump("杀掉的子进程",$pid);
            unset($this->worker_pid[$index]);
            $this->fork(1); //重新拉起worker
        }

    }

    //捕获信号之后结束进程
    public function stopAll(){
        foreach ($this->worker_pid as $index=>$pid){
            posix_kill($pid,SIGKILL); //结束进程
            var_dump($pid.'关闭');
            unset($this->worker_pid[$index]);
        }
    }
}
$worker = new Worker('tcp://0.0.0.0:9998');


$worker->start(); //启动

运行结果及报错内容
我的解答思路和尝试过的方法
我想要达到的结果

让进程监听文件修改状态的同时监听信号以及子进程的异常退出

  • 写回答

1条回答 默认 最新

  • 有问必答小助手 2021-11-25 16:08
    关注

    你好,我是有问必答小助手,非常抱歉,本次您提出的有问必答问题,技术专家团超时未为您做出解答


    本次提问扣除的有问必答次数,将会以问答VIP体验卡(1次有问必答机会、商城购买实体图书享受95折优惠)的形式为您补发到账户。


    因为有问必答VIP体验卡有效期仅有1天,您在需要使用的时候【私信】联系我,我会为您补发。

    评论

报告相同问题?

问题事件

  • 系统已结题 12月2日
  • 创建了问题 11月24日

悬赏问题

  • ¥15 c程序不知道为什么得不到结果
  • ¥40 复杂的限制性的商函数处理
  • ¥15 程序不包含适用于入口点的静态Main方法
  • ¥15 素材场景中光线烘焙后灯光失效
  • ¥15 请教一下各位,为什么我这个没有实现模拟点击
  • ¥15 执行 virtuoso 命令后,界面没有,cadence 启动不起来
  • ¥50 comfyui下连接animatediff节点生成视频质量非常差的原因
  • ¥20 有关区间dp的问题求解
  • ¥15 多电路系统共用电源的串扰问题
  • ¥15 slam rangenet++配置