Bug #67913 [Opn->Csd]: mysqlnd ignores MYSQLI_OPT_CONNECT_TIMEOUT option
| From: | dharman@php.net | Date: | Fri, 11 Dec 2020 22:41:19 +0000 |
| Subject: | Bug #67913 [Opn->Csd]: mysqlnd ignores MYSQLI_OPT_CONNECT_TIMEOUT option | ||
| References: | 1 | Groups: | php.bugs |
| Request: | Send a blank email to php-bugs+get-231030@lists.php.net to get a copy of this message | ||
Edit report at https://bugs.php.net/bug.php?id=67913&edit=1
ID: 67913
Updated by: dharman@php.net
Reported by: ablyler at barracuda dot com
Summary: mysqlnd ignores MYSQLI_OPT_CONNECT_TIMEOUT option
-Status: Open
+Status: Closed
Type: Bug
-Package: MySQL related
+Package: MySQLi related
Operating System: Any
PHP Version: 5.5.16
-Assigned To:
+Assigned To: dharman
Block user comment: N
Private report: N
New Comment:
Thanks for the bug report and patch. I have decided to close this report as I can't reproduce
this issue anymore. I am not 100% sure whether the issue you have reported was fixed completely, but
given that the suggested patch and follow-up comment talked about READ_TIMEOUT I guess you meant
that there was no way to set MYSQLI_OPT_READ_TIMEOUT before PHP 7.2. This option has been added and
is now documented, but if the issue persists we can reopen this bug report in future.
Previous Comments:
------------------------------------------------------------------------
[2018-06-18 23:02:46] php at darkain dot com
https://bugs.php.net/bug.php?id=76497
Solved by using the (currently undocumented) MYSQLI_OPT_READ_TIMEOUT option.
------------------------------------------------------------------------
[2018-04-24 17:33:10] php at darkain dot com
This bug still persists in PHP 7.2.4. This is more than just a bug, it in effect DoSed a production
system I manage.
I run a series of MariaDB nodes in a Galera cluster. One of the nodes misbehaved. This happens from
time to time. When a connection issue happens normally with a Galera node, it is pulled out of the
local list of available nodes stored on each PHP instance. This process of storing and updating the
list of Galera nodes is handled within a PHP script based on successful/failure to connect to each
node. The problem is that even with MYSQLI_OPT_CONNECT_TIMEOUT set, no timeout happens if a
successful TCP handshake is made but no data is transmitted over the wire afterwards. PHP is left in
a hung state that can only be broken by restarting the entire PHP-FPM service. This leads to an
eventual resource exhaustion within PHP-FPM hitting its maximum open connection limit as more users
access the web site. This eventually breaks the entire web site.
Simple code to reproduce:
$sql = mysqli_init();
$sql->options(MYSQLI_OPT_CONNECT_TIMEOUT, 1);
$sql->real_connect('google.com:80', 'user', 'my_password',
'db');
echo 'GOOD';
NOTE that using a web server such as google.com, the server side will eventually break the
connection. HOWEVER, the short timeout of 1 second never happens, and instead the server side breaks
the connection after the server side timeout value. In the case of MariaDB with the single node that
misbehaved, it never broke the connection. Instead, no data was ever transmitted over the wire after
the TCP handshake, leaving PHP in an endless waiting process. Nothing after $sql->real_connect()
is ever processed, therefor any sysadmin related emails about a failed connection or automatically
pulling the failed node from the server pool ever happened as a result.
------------------------------------------------------------------------
[2014-08-26 22:55:44] ablyler at barracuda dot com
Description:
------------
The MYSQLI_OPT_CONNECT_TIMEOUT is ignored when using mysqlnd. To reproduce this run:
netstat -l -p 9999
Then execute the included test script (wrapped with time).
Thanks to Jason Dictos for coming up with the fix to this.
Test script:
---------------
<?php
$connect_timeout = 5;
$resource = mysqli_init();
if (!mysqli_options($resource, MYSQLI_OPT_CONNECT_TIMEOUT, $connect_timeout))
{
die('Unable to set connect timeout on resource');
}
var_dump(mysqli_real_connect($resource, '127.0.0.1', 'username',
'password', 'database', 9999));
Expected result:
----------------
It should return in ~5 seconds with errors.
Actual result:
--------------
The script will keep running past the timeout value.
------------------------------------------------------------------------
--
Edit this bug report at https://bugs.php.net/bug.php?id=67913&edit=1