Swoole如何在使用了Server后实现一个可优雅退出的while(true)

前言

目前使用swoole的Server做了一个TCP的服务端,然后产生了一个比较特殊的需求,需要某几个进程去长时间while(true)去执行任务。

目前的方案

  1. swoole提供的task进程,在onwoker事件直接进入while循环,然后执行任务
  2. swoole提供的task进程,在进程启动完毕后,使用worker0进程投递任务到task进程,然后触发task内的while循环.
  • 以上是目前试过的2个方案.
  • 但是,测试发现1和2都无法响应SIGTERM与SIGUSR1,因为业务死循环了,swoole发了信号给子进程,等待退出,但是子进程在死循环.
  • 于是,又加上了pcntl扩展设置了一个异步信号,当监听到信号时将某个变量置为0 然后while检查到0就退出.

遇到了的问题

  • 经过测试,发现while成功退出了,数据也收回了,没有接下来的业务代码了,但是swoole的主进程却没有收回进程。【不确定是否为pcntl扩展导致信号覆盖造成的bug所以暂时没有提交】
  • 发现这个问题后,主动使用SIGKILL对自身进行了自杀,然后发现swoole成功拉起了新的进程去做工
  • 看似一切都解决了没有问题,但是没想到在进程持续工作20分钟后突然会出现假死,又或者重载后进程执行一次任务直接假死,反复几次重载后又不假死

求知

  1. 有其它可以执行while死循环又可以优雅跟随信号退出的方案吗?(另写一个专门的进程组去做任务然后再通信给serv的的做法很不符合现有需求,所以不考虑)
  2. 到底为什么会卡住?(不会是业务代码的问题,业务代码测试过只echo 一句话也会复现)
  3. 卡住之后发送SIGTERM能够结束服务,但是再次运行会发现先输出了上次卡住之后的阻塞内容,然后才输出了系统正常启动后的内容,这是为什么呢
这个疑问是源自需要while死循环,所以设置投递抢占然后去投递的概念没必要有,上面的投递任务去触发while只是单纯为了进入task然后不断检查执行,而不是为了投递,是测试进程卡住排除错误使用才那样干了一次
if($worker_id == 0){
    go(function() use($serv){
        for ($i=0; $i < SYSTEM_TASK; $i++) { 
            $serv->task('',$i);
        }
    });
}

只是为了进入task...

阅读 680
评论 更新于 1月18日
    1 个回答

    你需要在 for 循环中加入一个条件判断,在一定情况下退出循环。

    如果是跨进程操作可以使用 Atomic 模块

    评论 赞赏 1月18日
      撰写回答

      登录后参与交流、获取后续更新提醒