Implementation of the server’s health check in Yii 2.0
1. In Yii 2.0, the realization of health check, a colleague implemented a version before, I feel that it is necessary to adjust it again
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. The analysis code found that yii::$app->db->getisActive() is unnecessary. View the source code of the corresponding method separately. The related implementation of $this->pdo in getIsActive() already exists in 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. Analyze the code to find, use the command line directly. Redis has many useful commands that can be used directly from the connection. ping exists in the list of available redis commands. This command is often used to test whether a connection is still available, or to test the delay of a connection. as shown in Figure 1
4. In Yii 2.0, the realization of health check, the version after adjustment
Yii::$app->db->open();
Yii::$app->redis->open();
return 200;
5. Change the password of DB to wrong, and the response is 500 as follows, which is in line with expectations. as shown in Figure 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. Change the password of Redis to wrong, and the response is 500 as follows, which is in line with expectations. Replace yii::$app->redis->open(); with: yii::$app->redis->ping() , the response is the same, the reason is that the ping is executing Before the command, you need to execute open() first. as shown in Figure 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. To sum up, whether it is the check of the connection of DB or Redis. It is best to maintain a uniform detection method. Therefore, the open() method is uniformly adopted. yii::$app->db->getisActive() is unnecessary, it is a redundant implementation.


