Gateway异常退出问题及解决方案

zzz

在项目运行中遇到不定时出现这个问题,目前已解决,问题如下:
 Gateway.php:372

 if ($this->_workerConnections) {
    // 调用路由函数,选择一个worker把请求转发给它
    /** @var TcpConnection $worker_connection */
    $worker_connection = call_user_func($this->router, $this->_workerConnections, $connection, $cmd, $body);
    if (false === $worker_connection->send($gateway_data)) {
        $msg = "SendBufferToWorker fail. May be the send buffer are overflow. See http://wiki.workerman.net/Error2";
        static::log($msg);
        return false;
    }
} 

// 没有可用的 worker此时判断了$this->_workerConnections是否为真,如果为真就去调用了路由函数
 
如果此时reload,用户有多个worker进程,并且自定义了路由,需要把用户路由到特定worker进程
 
那么此时在$this->_workerConnections中很有可能不是全部已启动好的worker

其中可能因为需要worker进程未加载完成,所以并不包含需要的worker进程 

这时就有可能会出现一个致命错误:null调用了不存在的方法send()
 
因此需要修改一下这个判断是否有可用worker的if判断:

if ($this->_workerConnections) {
    // 调用路由函数,选择一个worker把请求转发给它
    /** @var TcpConnection $worker_connection */
    $worker_connection = call_user_func($this->router, $this->_workerConnections, $connection, $cmd, $body);
    if (!$worker_connection) {
        do {
            $worker_connection = call_user_func($this->router, $this->_workerConnections, $connection, $cmd, $body);
        } while(!$worker_connection);
    }
    if (false === $worker_connection->send($gateway_data)) {
        $msg = "SendBufferToWorker fail. May be the send buffer are overflow. See http://wiki.workerman.net/Error2";
        static::log($msg);
        return false;
    }
} 

// 没有可用的 worker麻烦walkor看看,希望在框架中修复,这样我们就不用侵入去修改框架的代码,造成后续git更新框架的困扰

3425 2 0
2个回答

walkor 打赏

感谢你的建议,

if (!$worker_connection) {
    do {
        $worker_connection = call_user_func($this->router, $this->_workerConnections, $connection, $cmd, $body);
    } while(!$worker_connection);
}

不过这个代码无法解决你说的这个问题。原因是进程执行在这个死循环时,这些参数 $this->router, $this->_workerConnections, $connection, $cmd, $body是不变的,尤其是$this->_workerConnections不会有变化,这会导致gateway进程cpu100%,导致服务永远无法使用。
 
框架能优化的只能是判断下 $worker_connection 是否为空,如果为空就不调用send,并记录一个日志。
 
 

  • 暂无评论
zzz

谢谢回复,那是否能将发送失败的消息放入一个队列,后续按一定的重试次数重试发送,如果重试成功或者重试失败一定次数就移除消息呢

  • walkor 2019-07-19

    可以的,你们可以自己加个

年代过于久远,无法发表回答
×
🔝