E_WARNING: Error while sending STMT_PREPARE packet. PID=*

前端 未结 4 727
一个人的身影
一个人的身影 2021-02-05 17:32

As of 2019-01-30 14:52 UTC, you can still win the 500-point Bounty because none of the answers have helped!

My Laravel 5.7 website has been experiencing a few problems

4条回答
  •  暗喜
    暗喜 (楼主)
    2021-02-05 17:48

    I encountered the same situation on a long-running PHP CLI script (it listens on a Redis list ; each action is quick but the script basically runs for ever).

    I create the PDO object and a prepared statement at the beginning, then reuse them afterwards.

    The day after I started the script, I got the exact same errors:

    PHP Warning:  Error while sending STMT_EXECUTE packet. PID=9438 in /...redacted.../myscript.php on line 39
    
    SQLSTATE[HY000]: General error: 2006 MySQL server has gone away
    

    In my case, it's a development server, there is no load, MySQL is on the same box... so it's unlikely to come from external factors. It's most likely related to the fact I used the same MySQL connection for too long, and it timed out. And PDO doesn't bother, so any subsequent query will just return "MySQL server has gone away".

    Checking the value of "wait_timeout" in MySQL:

    mysql> show variables like 'wait_timeout';
    +---------------+-------+
    | Variable_name | Value |
    +---------------+-------+
    | wait_timeout  | 28800 |
    +---------------+-------+
    1 row in set (0.06 sec)
    
    mysql> show local variables like 'wait_timeout';
    +---------------+-------+
    | Variable_name | Value |
    +---------------+-------+
    | wait_timeout  | 28800 |
    +---------------+-------+
    1 row in set (0.00 sec)
    

    I see 28800 seconds = 8 hours, which seems coherent with the timing of my errors.

    In my case, restarting the MySQL server, or setting wait_timeout very low, while keeping the same PHP worker running, makes it very easy to reproduce the issue.

    Overall:

    • PDO doesn't care if the connection times out, and will not automatically reconnect. If you put a try/catch around your PDO queries, the script will never crash and keep using the obsolete PDO instance.
    • the STMT_EXECUTE warning is probably incidental ; just because the script whose connection timed out was using prepared statements, and the first query post-timeout happened to be using a prepared statement

    To get back to your case

    • in theory Laravel 5 is immune to this issue: https://blog.armen.im/en/laravel-4-and-stmt_prepare-error/ ; do you use something other than Illuminate, or even bare PDO directly? Also, I'm not sure what Laravel does when it detects a lost connection (does it reconnect and rebuild prepared statements?), it might be worth digging further.
    • check your MySQL wait_timeout value, and increase it if it's too low
    • if it's not happening all the time, see if the errors correlate with server / DB load. High load can make things (especially big SQL queries) several times slower, to the point some other MySQL timeout like max_execution_time gets reached.
    • see if you wrapped PDO queries in a try / catch block and use it to retry the query ; it might be preventing the connection error from bubbling up.

提交回复
热议问题