1

We are trying to terminate a PHP script upon fatal error so the script can be restarted by Supervisor. The following is our exception handler:

    public function exceptionHandler(\Throwable $e)
    {
        if(Config::get('APP_DEBUG')) {
            echo (date("Y-m-d H:i:s").", uncaught exception in WsApp: ".$e->getMessage().PHP_EOL."");
        } else {
            \Sentry\captureException($e);
        }

        //exec('kill -9 ' . getmypid());
        exit("tried to exit from WsApp\r\n");
    }

The PHP script depends on MySQL server. If I stop MySQL server before running this PHP script, I get the following output in terminal:

2023-08-25 20:18:13, exception happened when trying to setupConn, SQLSTATE[HY000] [2002] No such file or directory
2023-08-25 20:18:13, uncaught exception in WsApp: Failed to setup connection to local DB.
tried to exit from WsApp // indication that error handler actually ran
^C // script continued to run until terminated by Ctrl + C

It seems exit in the error handler doesn't really terminal the script itself until I press Ctrl + C on keyboard.

The following is our code that throws exception upon failure to establish connection to DB server:

        try {
            $this->dbConn = new \PDO($dsn, Config::get('DB_USER_BI'), Config::get('DB_PW_BI'), $options);
        } catch (\Throwable $th) {
            if(Config::get('APP_DEBUG')) {
                echo date("Y-m-d H:i:s").", exception happened when trying to setupConn, ".$th->getMessage().PHP_EOL."";
            }
            // If a local DB connection cannot be established
            // Then there is no point to run any script
            throw new \Exception('Failed to setup connection to local DB.');
        }

But the following line as suggested by another post actually does the job.

exec('kill -9 ' . getmypid());

I get the following output in terminal:

2023-08-25 20:16:14, exception happened when trying to setupConn, SQLSTATE[HY000] [2002] No such file or directory
2023-08-25 20:16:14, uncaught exception in WsApp: Failed to setup connection to local DB.
Killed // output of exec(...)

My question is, why exit() doesn't terminate the script? My understanding is that exit will terminate the entire process.

Also what would be the consequence of running the following line? Memory leak because class destructor doesn't get to run?

exec('kill -9 ' . getmypid());

Please advise, thanks.

13
  • 1
    My guess is that it's trying to close its connection to the database, and this is hanging. Commented Aug 25, 2023 at 20:37
  • Don't use kill -9 if you can avoid it. Just use kill. This sends the same signal that typing Ctrl-C does. Commented Aug 25, 2023 at 20:38
  • Hi @Barmar thanks for your quick response and suggestion. I just included our code to setup db connection. Do you think PDO will try to close connection even if a connection is not established? Commented Aug 25, 2023 at 20:44
  • 1
    You may need to use a system call trace to see where it's stuck. Commented Aug 25, 2023 at 20:46
  • 1
    Maybe is ZeroMQ that is still hanging for some reasons. Have you tried to set a value for ZMQ::SOCKOPT_LINGER (before connect())? Something like this $socket->setSockOpt(ZMQ::SOCKOPT_LINGER, 10); php.net/manual/en/class.zmq.php#zmq.constants.sockopt-linger Commented Aug 25, 2023 at 23:57

1 Answer 1

1

After commenting out various blocks of code in the script, then moving them around, the problem is tracked down to something related to ZMQ.

If the code to setup DB connection is called before the 3rd line of code below:

$gwLoop = React\EventLoop\Loop::get();
$gwContext = new Context($gwLoop);
$msgAckPuller = $gwContext->getSocket(ZMQ::SOCKET_PULL);

Then exit() works as expected. If the code to setup DB connection is called after the 3rd line of code or any code like the following:

getSocket(ZMQ::SOCKET_PULL);

Then exit() will hang.

Calling DB connection code after any number of lines of code to

getSocket( ZMQ::SOCKET_PUSH)

appears to trigger exit() to work just fine.

Setting ZMQ::SOCKOPT_LINGER doesn't seem to prevent exit() from hanging:

$msgAckPuller->setSockOpt(ZMQ::SOCKOPT_LINGER, 10);

My knowledge about ZMQ and ReactPHP is limited, so I just close the question and leave the information above for future reference.

I reported this issue with a minimum test code to React's repo on GitHub.

use React\ZMQ\Context;

require dirname(__DIR__).'/vendor/autoload.php';

$testLoop = React\EventLoop\Loop::get();
$testContext = new Context($testLoop);

$testPusher = $testContext->getSocket(ZMQ::SOCKET_PUSH);
$testPusher->bind('tcp://127.0.0.1:5555');

//exit("exited after ZMQ:SOCKET_PUSH / before ZMQ::SOCKET_PULL\r\n");

$testPuller = $testContext->getSocket(ZMQ::SOCKET_PULL);

exit("tried to exit after ZMQ::SOCKET_PULL\r\n");

$testPuller->bind('tcp://127.0.0.1:5557');

Thanks everyone for participating in the discussion.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.