Workerman 5 errorHandler 为啥要绑定每个TCP连接上?

meows

问题描述

class TcpConnection {
    public $errorHandler = null;
    public function error(Throwable $exception): void
    {
        if (!$this->errorHandler) {
            Worker::stopAll(250, $exception);
            return;
        }
        try {
            ($this->errorHandler)($exception);
        } catch (Throwable $exception) {
            if ($this->eventLoop instanceof Event) {
                echo $exception;
                return;
            }
            throw $exception;
        }
    }
}
为什么不直接设置为全局Handler,比如:

    $worker = new Worker("http://0.0.0.0:8888");
    $worker->errorHandler = function($e) {
        Worker::log(xxx);
    }
    或者这样
    Worker::$errorHandler = function($e) {write log..}

class Worker {
    public $errorHandler = null;
    // 或者下面这样呢?
    // public static $errorHandler = null;
    public static function error(Throwable $exception): void
    {
        if (!$this->errorHandler) {
            Worker::stopAll(250, $exception);
            return;
        }
        try {
            ($this->errorHandler)($exception);
        } catch (Throwable $exception) {
            if (static::$globalEvent instanceof Event) {
                echo $exception;
                return;
            }
            throw $exception;
        }
    }
}

// 这样做不是更加节省内存,性能更好一些。但每个TCP都绑定errorHandler有其它原因呢?
// 如果在长连接场景,连接都不断开errorHandler会存在挺多,全局这样就只有一份。
438 1 0
1个回答

walkor

为了解耦,方便给每个连接定制化错误处理,还有方便做单元测试。
$errorHandler = 'myHanlder'; 这种不会占用多少内存。

  • meows 2023-10-07

    try {
    // Decode request buffer before Emitting onMessage callback.
    /* @var ProtocolInterface $parser /
    $parser = $this->protocol;
    $request = $parser::decode($oneRequestBuffer, $this);
    if (static::$enableCache && (!is_object($request) || $request instanceof Request) && $one && !isset($oneRequestBuffer[512])) {
    $requests[$oneRequestBuffer] = $request;
    if (count($requests) > 512) {
    unset($requests[key($requests)]);
    }
    }
    ($this->onMessage)($this, $request);
    } catch (Throwable $e) {
    $this->error($e);
    }

    如果 deocde 抛出异常,worker 会被干掉,这样是不是不太好!
    不是守护进程模式,直接echo $exception, 守护进程直接写入日志文件这样不是更加好?
    这样退出进程然后输出到终端有什么原因?

  • walkor 2023-10-07

    协议解析出问题是致命问题

  • meows 2023-10-11

    $worker->reloadable = false; 本身是不是无效的,亲测无效。
    $worker->reloadable = true; worker 退出重启修改代码文件有效,亲测可行。
    我感觉reloadable 属性设置为false没有意义呢。

    我理解的原理:
    master 启动时候include 所有文件,worker 继承 master 所有加载的文件,然后重新读取常驻内存。
    如果不重启worker,就还是常驻内存之前的效果一样的吧!
    https://www.workerman.net/doc/workerman/worker/reloadable.html 这篇文章链接reloadable = false 是不是需要改一改?
    应该是没有用的,没办法更新业务代码。

    “设置gateway进程的reloadable属性为false则在reload可以做到在不断开客户端连接的情况下更新业务代码。”
    这句话是不是应该删除掉,好像没有用呢。

  • admin 2023-10-12

    哥们是不是阅读理解有问题,

    执行php start.php reload时会向所有子进程发送reload信号(SIGUSR1)。

    这个reloadable 属性是用来 人工设置是否响应reload 代码,gatewayworker模式下gateway不能reload因为用户长链接这个gateway, 而bussiness需要reload,register也不需要reload。所以明白了吗

    如果只有一种类型的进程 这个reloadable 确实没啥用,多个不同类型的进程,有些需要reload,有些不需要懂了么。

    worker收到信号就会fork_new 然后include_once,因为是刚刚fork的,所以会重新读入代码

  • meows 2023-10-12

    感谢,懂了。哈哈哈

  • meows 2023-10-12
                  //  $worker->reloadable = false; 
                   // 开始没有明白这么做为了什么,感谢你的提醒,他就是为了执行下onWorkerReload() 业务,其它啥也没做。
                    foreach ($workerPidArray as $pid) {
                        // Send reload signal to a worker process which reloadable is false.
                        posix_kill($pid, $sig);
                    }
  • Tinywan 2023-10-12

    @admin 语文老师

🔝