Edit report at https://bugs.php.net/bug.php?id=80412&edit=1
ID: 80412
User updated by: heavy-traffic-website at yopmail dot com
Reported by: heavy-traffic-website at yopmail dot com
Summary: PHP-FPM : PDO / Broken Pipe when DBMS ends the
connection
-Status: Open
+Status: Closed
Type: Bug
Package: PDO Core
Operating System: Debian 11
PHP Version: 7.4.12
Block user comment: N
Private report: N
New Comment:
Ok, so, i now understand, seeing lot of PHP INTERNAL errors, but PDO still works.
nikic@php.net ; I supposed you have right.
Then, this was just surprising me, i thought PDO was not working fine but i seems it is. I will
suppress this error from the logs, and go on like that...
Thank you for support.
Previous Comments:
------------------------------------------------------------------------
[2020-11-26 10:52:45] heavy-traffic-website at yopmail dot com
Actual result:
--------------
string(26) "<BEFORE new PDO(), loop 1>"
string(34) "------------[ ERROR ]-------------"
string(79) "-- errstr: PDO::__construct(): send of 5 bytes failed with errno=32 Broken
pipe"
string(34) "----------------------------------"
string(25) "<AFTER new PDO(), loop 1>"
object(PDO)#2 (0) {
}
int(1)
string(26) "<BEFORE new PDO(), loop 2>"
string(25) "<AFTER new PDO(), loop 2>"
object(PDO)#3 (0) {
}
int(1)
string(26) "<BEFORE new PDO(), loop 3>"
string(25) "<AFTER new PDO(), loop 3>"
object(PDO)#2 (0) {
}
int(1)
string(26) "<BEFORE new PDO(), loop 4>"
string(25) "<AFTER new PDO(), loop 4>"
object(PDO)#3 (0) {
}
int(1)
string(26) "<BEFORE new PDO(), loop 5>"
string(25) "<AFTER new PDO(), loop 5>"
object(PDO)#2 (0) {
}
int(1)
string(26) "<BEFORE new PDO(), loop 6>"
string(25) "<AFTER new PDO(), loop 6>"
object(PDO)#3 (0) {
}
int(1)
------------------------------------------------------------------------
[2020-11-25 20:01:27] heavy-traffic-website at yopmail dot com
Description:
------------
Related to this very old bug reported 10 years ago
=> https://bugs.php.net/bug.php?id=53287
(johannes@php.net) was wrong - the bug still exists and no one fixed it.
--> Please consider the bug onto the PHP side, not the DBMS side.
PHP (php7.4-fpm) have threads with broken persistent connections cached with PDO and this should try
to reconnect a new one connection rather than calling the error handler in the case where the pipe
is already broken, during opening a nwe connection using persistence. Maybe there is a leak, why
don't you free a broken pipe and try to reuse it ?
Also, the PDO::_construct() return a PDO objet (without throwing an Exception), but PHP rises an
E_NOTICE :
string(68) "PDO::__construct(): send of 5 bytes failed with errno=32 Broken pipe"
That seems to deal with a E_CORE_WARNING ; generated by the core of PHP.
Currently, there is NO SOLUTION UNLESS FORGET PERSITANCE, it sucks !
Test script:
---------------
ini_set("error_reporting", (string) E_ALL);
ini_set("display_errors", "On");
ini_set("display_startup_errors", "On");
ini_set("track_errors", "On");
function my_error($errno, $errstr, $errfile, $errline)
{
var_dump("------------[ ERROR ]-------------");
var_dump("-- errstr: " . $errstr);
var_dump("----------------------------------");
}
set_error_handler("my_error");
abstract class Database
{
private static ?PDO $_db = null;
final public static function test() : ?PDO
{
for ($i = 1 ; $i <=6 ; ++$i)
{
var_dump("<BEFORE new PDO(), loop $i>");
try {
self::$_db = new PDO("mysql:host=127.0.0.1;dbname=XXX",
"XXX", "XXX", [
PDO::ATTR_PERSISTENT => true,
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
]);
}
catch (PDOException $e) {
var_dump("----------[ EXCEPTION ]-----------");
var_dump("-- excstr: " . $e->getMessage());
var_dump("----------------------------------");
}
var_dump("<AFTER new PDO(), loop $i>")
var_dump(self::$_db);
var_dump("<PING select, loop $i>");
var_dump(self::$_db->query("SELECT 1")->rowCount());
}
return self::$_db;
}
}
Database::test();
Expected result:
----------------
string(26) "<BEFORE new PDO(), loop 1>"
string(25) "<AFTER new PDO(), loop 1>"
object(PDO)#2 (0) {
}
string(21) "<PING select, loop 1>"
int(1)
string(26) "<BEFORE new PDO(), loop 2>"
string(25) "<AFTER new PDO(), loop 2>"
object(PDO)#4 (0) {
}
string(21) "<PING select, loop 2>"
int(1)
string(26) "<BEFORE new PDO(), loop 3>"
string(25) "<AFTER new PDO(), loop 3>"
object(PDO)#3 (0) {
}
string(21) "<PING select, loop 3>"
int(1)
string(26) "<BEFORE new PDO(), loop 4>"
string(25) "<AFTER new PDO(), loop 4>"
object(PDO)#2 (0) {
}
string(21) "<PING select, loop 4>"
int(1)
string(26) "<BEFORE new PDO(), loop 5>"
string(25) "<AFTER new PDO(), loop 5>"
object(PDO)#4 (0) {
}
string(21) "<PING select, loop 5>"
int(1)
string(26) "<BEFORE new PDO(), loop 6>"
string(25) "<AFTER new PDO(), loop 6>"
object(PDO)#3 (0) {
}
string(21) "<PING select, loop 6>"
int(1)
Actual result:
--------------
< I AM DOING SOME TESTS NOW >
< Please wait for an update >
------------------------------------------------------------------------
[2020-11-25 15:22:18] heavy-traffic-website at yopmail dot com
Some precisons :
ini_set("error_reporting", (string) E_ALL);
ini_set("display_errors", "On");
ini_set("display_startup_errors", "On");
ini_set("track_errors", "On");
set_exception_handler("my_exception");
set_error_handler("my_error");
[ERROR HANDLER]
errno: int(8)
errstr: string(68) "PDO::__construct(): send of 5 bytes failed with errno=32 Broken pipe"
errfile: string(31) "/var/www/XXX/Database.class.php"
errline: int(28)
line 27 --> $db = new PDO("mysql:host=127.0.0.1;dbname=XXX", "XXX",
"XXX",
line 28 --> PDO::ATTR_PERSISTENT => true,
line 29 --> PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]);
------------------------------------------------------------------------
[2020-11-25 14:24:37] heavy-traffic-website at yopmail dot com
Thank you for your note.
The debate is not about the log itself, independantly the state of error_reporting is. For
developpment, mine is set to E_ALL and works fine, there is no error implementing that.
PHP can procude any warning that he wants, but fail to __contruct PDO after a broken pipe IS NOT A
NORMAL sence or wanted. You cannot tell each pipe connection will never end, so you made a mistake
in your configuration... or that is a desired effect.
There is no error somewhere due to the other parties. It can happen of a pipe is broken due to long
inactivity ; do network activities and you will know. Softwares have to retry retablishing the pipe
BEFORE throwing any error : it should be the same with PHP/PDO core.
If PHP/PDO fails to send data ; it is because the pipe onto the thread is cached (due to the
persistance), and reused like it should be always be working, it is incorrect.
When PHP/PDO have a "send of 5 bytes failed with errno=32", you should flush the cache
about persistent connexion then RETRYING __construct with persistant connection LIKE it has been a
new thread without cached yet.
If an error had to be throwed, it can be adjusted :
- "send of 5 bytes failed with errno=32", moreover, "server has gone away".
- "send of 5 bytes failed with errno=32", moreover, "[last connection error]".
This error will be consistent. But to let a thread with inconsistent broken pipe cached, is not
consistent neither wanted neither normal. By the way, you can't have 2 identical "Pipe
error" when retrying connection. So, it is logic to retry ONCE a persistent broken pipe.
------------------------------------------------------------------------
[2020-11-25 08:44:13] nikic@php.net
Just a note, if you see that "broken pipe" error, that probably means you have a broken
error handler implementation somewhere. This error is suppressed internally (error_reporting=0), but
an incorrectly implemented error handler that does not check the error_reporting level may make it
visible again.
------------------------------------------------------------------------
The remainder of the comments for this report are too long. To view
the rest of the comments, please view the bug report online at
https://bugs.php.net/bug.php?id=80412
--
Edit this bug report at https://bugs.php.net/bug.php?id=80412&edit=1