没有不值得去解决的问题,也没有不值得去学习的技术!

在 Yii 2.0 中,服务器的健康检查的实现

将 db 的密码修改为错误的,响应 500 如下,符合预期。
1、在 Yii 2.0 中,健康检查的实现,之前有同事实现了一个版本,感觉有必要再调整一下


        Yii::$app->db->open();
        if(!Yii::$app->redis->ping()) {
            throw new ServerErrorHttpException('error','Redis is unavailable.',500);
        } elseif(!Yii::$app->db->getIsActive()) {
            throw new ServerErrorHttpException('error','Database is unavailable.',500);
        } else {
            return 200;
        }


2、分析代码发现,Yii::$app->db->getIsActive() 无必要。分别查看相应方法的源码。getIsActive() 中的 $this->pdo 的相关实现已经存在于 open() 中。


    /**
     * Establishes a DB connection.
     * It does nothing if a DB connection has already been established.
     * @throws Exception if connection fails
     */
    public function open()
    {
        if ($this->pdo !== null) {
            return;
        }

        if (!empty($this->masters)) {
            $db = $this->getMaster();
            if ($db !== null) {
                $this->pdo = $db->pdo;
                return;
            }

            throw new InvalidConfigException('None of the master DB servers is available.');
        }

        if (empty($this->dsn)) {
            throw new InvalidConfigException('Connection::dsn cannot be empty.');
        }

        $token = 'Opening DB connection: ' . $this->dsn;
        $enableProfiling = $this->enableProfiling;
        try {
            if ($this->enableLogging) {
                Yii::info($token, __METHOD__);
            }

            if ($enableProfiling) {
                Yii::beginProfile($token, __METHOD__);
            }

            $this->pdo = $this->createPdoInstance();
            $this->initConnection();

            if ($enableProfiling) {
                Yii::endProfile($token, __METHOD__);
            }
        } catch (\PDOException $e) {
            if ($enableProfiling) {
                Yii::endProfile($token, __METHOD__);
            }

            throw new Exception($e->getMessage(), $e->errorInfo, (int) $e->getCode(), $e);
        }
    }

    /**
     * Returns a value indicating whether the DB connection is established.
     * @return bool whether the DB connection is established
     */
    public function getIsActive()
    {
        return $this->pdo !== null;
    }


3、分析代码发现,直接使用命令行。Redis 有很多可以直接从连接中使用的有用的命令。ping 存在于可用的 redis 命令列表中。这个命令经常用来测试一个连接是否还是可用的,或者用来测试一个连接的延时。如图1
分析代码发现,直接使用命令行。Redis 有很多可以直接从连接中使用的有用的命令。ping 存在于可用的 redis 命令列表中。这个命令经常用来测试一个连接是否还是可用的,或者用来测试一个连接的延时。
图1
4、在 Yii 2.0 中,健康检查的实现,调整之后的版本


            Yii::$app->db->open();
            Yii::$app->redis->open();
            return 200;


5、将 db 的密码修改为错误的,响应 500 如下,符合预期。如图2
将 db 的密码修改为错误的,响应 500 如下,符合预期。
图2


{
    "name": "Database Exception",
    "message": "SQLSTATE[HY000] [1045] Access denied for user 'pcs-api'@'localhost' (using password: YES)",
    "code": 1045,
    "type": "yii\\db\\Exception",
    "file": "E:\\wwwroot\\pcs-api\\vendor\\yiisoft\\yii2\\db\\Connection.php",
    "line": 637,
    "stack-trace": [
        "#0 E:\\wwwroot\\pcs-api\\api\\rests\\openconf\\CreateAction.php(58): yii\\db\\Connection->open()",
        "#1 [internal function]: api\\rests\\openconf\\CreateAction->run()",
        "#2 E:\\wwwroot\\pcs-api\\vendor\\yiisoft\\yii2\\base\\Action.php(94): call_user_func_array(Array, Array)",
        "#3 E:\\wwwroot\\pcs-api\\vendor\\yiisoft\\yii2\\base\\Controller.php(157): yii\\base\\Action->runWithParams(Array)",
        "#4 E:\\wwwroot\\pcs-api\\vendor\\yiisoft\\yii2\\base\\Module.php(528): yii\\base\\Controller->runAction('create', Array)",
        "#5 E:\\wwwroot\\pcs-api\\vendor\\yiisoft\\yii2\\web\\Application.php(103): yii\\base\\Module->runAction('v1/openconf/cre...', Array)",
        "#6 E:\\wwwroot\\pcs-api\\vendor\\yiisoft\\yii2\\base\\Application.php(386): yii\\web\\Application->handleRequest(Object(yii\\web\\Request))",
        "#7 E:\\wwwroot\\pcs-api\\api\\web\\index.php(17): yii\\base\\Application->run()",
        "#8 {main}"
    ],
    "error-info": null,
    "previous": {
        "name": "Exception",
        "message": "SQLSTATE[HY000] [1045] Access denied for user 'pcs-api'@'localhost' (using password: YES)",
        "code": 1045,
        "type": "PDOException",
        "file": "E:\\wwwroot\\pcs-api\\vendor\\yiisoft\\yii2\\db\\Connection.php",
        "line": 705,
        "stack-trace": [
            "#0 E:\\wwwroot\\pcs-api\\vendor\\yiisoft\\yii2\\db\\Connection.php(705): PDO->__construct('mysql:host=loca...', 'pcs-api', 'jwpuOHTSX5hOcuX...', NULL)",
            "#1 E:\\wwwroot\\pcs-api\\vendor\\yiisoft\\yii2\\db\\Connection.php(626): yii\\db\\Connection->createPdoInstance()",
            "#2 E:\\wwwroot\\pcs-api\\api\\rests\\openconf\\CreateAction.php(58): yii\\db\\Connection->open()",
            "#3 [internal function]: api\\rests\\openconf\\CreateAction->run()",
            "#4 E:\\wwwroot\\pcs-api\\vendor\\yiisoft\\yii2\\base\\Action.php(94): call_user_func_array(Array, Array)",
            "#5 E:\\wwwroot\\pcs-api\\vendor\\yiisoft\\yii2\\base\\Controller.php(157): yii\\base\\Action->runWithParams(Array)",
            "#6 E:\\wwwroot\\pcs-api\\vendor\\yiisoft\\yii2\\base\\Module.php(528): yii\\base\\Controller->runAction('create', Array)",
            "#7 E:\\wwwroot\\pcs-api\\vendor\\yiisoft\\yii2\\web\\Application.php(103): yii\\base\\Module->runAction('v1/openconf/cre...', Array)",
            "#8 E:\\wwwroot\\pcs-api\\vendor\\yiisoft\\yii2\\base\\Application.php(386): yii\\web\\Application->handleRequest(Object(yii\\web\\Request))",
            "#9 E:\\wwwroot\\pcs-api\\api\\web\\index.php(17): yii\\base\\Application->run()",
            "#10 {main}"
        ]
    }
}


6、将 redis 的密码修改为错误的,响应 500 如下,符合预期。将 Yii::$app->redis->open(); 替换为:Yii::$app->redis->ping() ,响应是一样的,原因为在执行 ping 命令之前,需要先执行 open()。如图3
将 redis 的密码修改为错误的,响应 500 如下,符合预期。将 Yii::$app->redis->open(); 替换为:Yii::$app->redis->ping() ,响应是一样的,原因为在执行 ping 命令之前,需要先执行 open()。
图3


{
    "name": "Database Exception",
    "message": "Redis error: ERR Client sent AUTH, but no password is set\nRedis command was: AUTH 88888888",
    "code": 0,
    "type": "yii\\db\\Exception",
    "file": "E:\\wwwroot\\pcs-api\\vendor\\yiisoft\\yii2-redis\\src\\Connection.php",
    "line": 821,
    "stack-trace": [
        "#0 E:\\wwwroot\\pcs-api\\vendor\\yiisoft\\yii2-redis\\src\\Connection.php(789): yii\\redis\\Connection->parseResponse(Array, '*2\\r\\n$4\\r\\nAUTH\\r\\n$...')",
        "#1 E:\\wwwroot\\pcs-api\\vendor\\yiisoft\\yii2-redis\\src\\Connection.php(772): yii\\redis\\Connection->sendCommandInternal('*2\\r\\n$4\\r\\nAUTH\\r\\n$...', Array)",
        "#2 E:\\wwwroot\\pcs-api\\vendor\\yiisoft\\yii2-redis\\src\\Connection.php(634): yii\\redis\\Connection->executeCommand('AUTH', Array)",
        "#3 E:\\wwwroot\\pcs-api\\vendor\\yiisoft\\yii2-redis\\src\\Connection.php(744): yii\\redis\\Connection->open()",
        "#4 E:\\wwwroot\\pcs-api\\vendor\\yiisoft\\yii2-redis\\src\\Connection.php(709): yii\\redis\\Connection->executeCommand('PING', Array)",
        "#5 E:\\wwwroot\\pcs-api\\api\\rests\\openconf\\CreateAction.php(57): yii\\redis\\Connection->__call('ping', Array)",
        "#6 [internal function]: api\\rests\\openconf\\CreateAction->run()",
        "#7 E:\\wwwroot\\pcs-api\\vendor\\yiisoft\\yii2\\base\\Action.php(94): call_user_func_array(Array, Array)",
        "#8 E:\\wwwroot\\pcs-api\\vendor\\yiisoft\\yii2\\base\\Controller.php(157): yii\\base\\Action->runWithParams(Array)",
        "#9 E:\\wwwroot\\pcs-api\\vendor\\yiisoft\\yii2\\base\\Module.php(528): yii\\base\\Controller->runAction('create', Array)",
        "#10 E:\\wwwroot\\pcs-api\\vendor\\yiisoft\\yii2\\web\\Application.php(103): yii\\base\\Module->runAction('v1/openconf/cre...', Array)",
        "#11 E:\\wwwroot\\pcs-api\\vendor\\yiisoft\\yii2\\base\\Application.php(386): yii\\web\\Application->handleRequest(Object(yii\\web\\Request))",
        "#12 E:\\wwwroot\\pcs-api\\api\\web\\index.php(17): yii\\base\\Application->run()",
        "#13 {main}"
    ],
    "error-info": []
}


7、总结,不论是 db 还是 redis 的连接的检查。最好能够保持统一的检测方式。因此,统一采用 open() 方法。而 Yii::$app->db->getIsActive() 无必要,是冗余的实现。

PHP / Laravel / Yii2 老项目维护与长期技术支持

如果你的 PHP / Laravel / Yii2 项目已经上线,但遇到原开发离职、Bug 长期无人修复、接口不稳定、性能下降、代码难以接手等问题,可以联系我做一次远程技术排查。

适合以下情况:
✅ 老旧 PHP 系统无人维护
✅ Laravel / Yii2 项目 Bug 修复
✅ 后台管理系统小功能迭代
✅ RESTful API 接口排查
✅ MySQL / Redis / Nginx 性能问题
✅ 长期远程兼职维护

可先从一次小问题开始:
✅ 线上报错排查
✅ 接口异常分析
✅ 慢查询与性能瓶颈定位
✅ 代码结构初步评估
✅ 部署环境与日志检查

如需咨询,请联系我,并注明:PHP 维护咨询

联系方式:
Telegram:@shuijingwan
微信:13980074657
邮箱:shuijingwanwq@gmail.com

评论

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

这个站点使用 Akismet 来减少垃圾评论。了解你的评论数据如何被处理