Bug #78972 [Ver]: Using disconnected PDO connection causes suppressed EPIPE notice
| From: | nikic@php.net | Date: | Thu, 29 Oct 2020 13:42:22 +0000 |
| Subject: | Bug #78972 [Ver]: Using disconnected PDO connection causes suppressed EPIPE notice | ||
| References: | 1 | Groups: | php.bugs |
| Request: | Send a blank email to php-bugs+get-230006@lists.php.net to get a copy of this message | ||
Edit report at https://bugs.php.net/bug.php?id=78972&edit=1
ID: 78972
Updated by: nikic@php.net
Reported by: xzzll at msn dot cn
-Summary: Pdo close error
+Summary: Using disconnected PDO connection causes suppressed
EPIPE notice
Status: Verified
Type: Bug
Package: PDO Core
Operating System: Centos7
PHP Version: 7.3.12
Block user comment: N
Private report: N
New Comment:
I don't think we have a good mechanism to suppress this more thoroughly right now.
It should be said that any error handler that does not ignore errors disabled by the current
error_reporting level is a buggy error handler. While it would be nice to improve the behavior here
on the mysqlnd side, the bug is ultimately in the custom error handler.
Previous Comments:
------------------------------------------------------------------------
[2020-10-29 13:31:58] nikic@php.net
Here is a reduced reproducer:
<?php
set_error_handler(function(...$args) {
var_dump(error_reporting());
var_dump($args);
});
$db = new \PDO('mysql:unix_socket=/var/run/mysqld/mysqld.sock;dbname=test',
'root', '', [
\PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION
]);
$db->exec('SET session wait_timeout=1');
sleep(2);
$db = null;
Something worth noting is that the broken pipe error is actually suppressed with error_reporting=0,
but of course it can still be seen by a custom error handler. It would be better to suppress it more
thoroughly.
------------------------------------------------------------------------
[2019-12-16 16:15:09] xzzll at msn dot cn
Description:
------------
Errors in some cases when pdo ends the connection.
I can't locate the details of this issue for now because it happens randomly.
The demo code I provided is almost the same as the actual business code, they work persistently
under cli and perform close and reopen on timeout connections.
However, the connection may be interrupted automatically due to network fluctuations or server
timeouts.When the mysql connection in some processes is persistent and no activity is triggered
again, an exception occurs.(My mysql server is remote)
Msg : \Game\Sql\Pdo::close(): send of 5 bytes failed with errno=32 Broken pipe
Since the demo code is more than 20 lines, I scaled it. Please format it and view it. I am very
sorry for the trouble.
It is important to note that this problem does not absolutely recur, it happens randomly, and when
the problem occurs, it is in a long-term vacant state.
Test script:
---------------
<?php
namespace test;class Pdo{public static $db;public static $start;public static $timeout;
public static function init($config){try {
self::$db = new \PDO('mysql:dbname=' . $config['table'] .
';host=' . $config['server'] . ';port=' . $config['port'] .
';charset=utf8', $config['user'], $config['password'], [
\PDO::ATTR_PERSISTENT => false,
\PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION
]);
} catch (\Throwable $th) {var_dump($th);return;}
self::$start = time();self::$timeout = (self::$db->query('show variables like
"wait_timeout"')->fetch(MYSQLI_ASSOC))['Value'];
echo ("-------------------MYSQLConnect timeout=" . self::$timeout . "
ServerVersion=" . self::$db->query('select version()')->fetchColumn() .
"-------------------");}
public static function close(){self::$db = null;}
public static function uinit(){self::close();$time = microtime(true);echo
("-------------------ReConnect:" . $time .
"-------------------");self::init(require(__DIR__ .
'/think/config/MysqlConfig.php'));echo ("-------------------ConnectOk:" .
(microtime(true) - $time) . "-------------------");}
public static function test(){if (time() - self::$start >= self::$timeout)
{$this->uinit();}}
}
\test\Pdo::init(require_once __DIR__ . '/think/config/MysqlConfig.php');
sleep(\test\Pdo::$timeout + 10); //The time here should actually be very long
\test\Pdo::test(); //error
/*SyStemNotice:Code: 8
File: /root/Game/think/system/Sql/Pdo.php:29
Msg : \Game\Sql\Pdo::close(): send of 5 bytes failed with errno=32 Broken pipe*/
Expected result:
----------------
Ideally, it should close the connection normally, or end directly when the connection is
unavailable, so that the code can continue to perform the connection work, but in fact it throws a
notice error
Actual result:
--------------
/*
SyStemNotice:
Code: 8
File: /root/Game/think/system/Sql/Pdo.php:29
Msg : \Game\Sql\Pdo::close(): send of 5 bytes failed with errno=32 Broken pipe
*/
------------------------------------------------------------------------
--
Edit this bug report at https://bugs.php.net/bug.php?id=78972&edit=1