0

I am trying to get a long running PHP script to work with MySQL server. Upon initialization of the script, a new PDO connection to MySQL server will be created. By following instruction from Mr.Bill Karwin in his following post: PDO: How to check if connection is active, for real?

Every time before this PDO connection is used, whether the connection is still active will be checked through the following code:

    private function checkConn()
    {
        try {
            $this->dbConn->query("SELECT 1");  // line pointed to in error message.
        } catch (\Throwable $e) {
            $this->setupConn();
            \Sentry\captureException($e);
        }
    }

But somehow this try-catch block doesn't work. If the PDO connection has not been used for a while and MySQL server closes the connection or if MySQL server is shut down for testing, when the script tries to use PDO connection next time, it will fall onto global error handler set by set_error_handler(), as if try-catch is not there at all.

Error message: PDO::query(): send of 13 bytes failed with errno=32 Broken pipe In file: DbOp.php line:62

I am running this script with PHP7.4.30 on Ubuntu 20.04 LTS, with the following PDO attributes:

\PDO::ATTR_TIMEOUT      => 1,
\PDO::ATTR_ERRMODE      => \PDO::ERRMODE_EXCEPTION,
\PDO::ATTR_PERSISTENT   => false

What am I missing here?

Please advise, thanks in advance.

Zhiyong Li
  • 469
  • 3
  • 14

1 Answers1

0

It turns out the problem is elsewhere. During base class initialization, a customized error handler is set:

set_error_handler(array($this, 'errorHandler'));

Without explicitly setting error_levels, all levels of errors, notices and warnings will be routed to errorHandler, therefore bypassing try-catch.

This therefore can be fixed by either setting a higher error_levels:

set_error_handler(array($this, 'errorHandler'), E_ALL & ~E_NOTICE & ~E_WARNING);

or temporally turning off error reporting as in Mr. Karwin's original post

    private function checkConn()
    {
        try {
            $old_errlevel = error_reporting(0);// This line is needed if customized error handler is set elsewhere
            $this->dbConn->query("SELECT 1");
        } catch (\Throwable $e) {
            exit(date("Y-m-d H:i:s").", uncaught exception: ".$e->getMessage()."\r\n");
            //$this->setupConn();
            //\Sentry\captureException($e);
        }
        error_reporting($old_errlevel);
    }
Zhiyong Li
  • 469
  • 3
  • 14
  • error handlers do not catch exceptions. and even exception handlers do not catch exceptions wrapped in try catch. Error handlers are last in the line – Your Common Sense Jul 26 '22 at 18:09
  • @YourCommonSense That's what I thought. But my test tells me otherwise. At least for PDO broken pipe error, and General error: 2006 MySQL server has gone away, that I tested, they will go directly to error handler, even when they are wrapped in try-catch. I suspect these errors are actually warning, not errors in PHP script itself. – Zhiyong Li Jul 26 '22 at 19:08