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.
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.