提问人:Zhiyong Li 提问时间:8/26/2023 最后编辑:Zhiyong Li 更新时间:8/26/2023 访问量:70
PHP 脚本不会在 exit() 时终止
PHP script doesn't terminate upon exit()
问:
我们试图在出现致命错误时终止 PHP 脚本,以便 Supervisor 可以重新启动该脚本。以下是我们的异常处理程序:
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");
}
PHP脚本依赖于MySQL服务器。如果我在运行此PHP脚本之前停止MySQL服务器,则会在终端中获得以下输出:
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
似乎错误处理程序中的退出并没有真正终止脚本本身,直到我在键盘上按 Ctrl + C。
以下是我们的代码,在无法与数据库服务器建立连接时抛出异常:
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.');
}
但是,正如另一篇文章所建议的那样,以下行实际上可以完成这项工作。
exec('kill -9 ' . getmypid());
我在终端中得到以下输出:
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(...)
我的问题是,为什么 exit() 不终止脚本?我的理解是退出将终止整个过程。
另外,运行以下行会有什么后果?内存泄漏,因为类析构函数无法运行?
exec('kill -9 ' . getmypid());
请指教,谢谢。
答:
1赞
Zhiyong Li
8/26/2023
#1
在注释掉脚本中的各种代码块,然后移动它们后,问题被追踪到与 ZMQ 相关的问题。
如果在下面的第 3 行代码之前调用用于设置数据库连接的代码:
$gwLoop = React\EventLoop\Loop::get();
$gwContext = new Context($gwLoop);
$msgAckPuller = $gwContext->getSocket(ZMQ::SOCKET_PULL);
然后 exit() 按预期工作。 如果设置数据库连接的代码在第 3 行代码或类似以下的任何代码之后调用:
getSocket(ZMQ::SOCKET_PULL);
然后 exit() 将挂起。
在任意数量的代码行后调用数据库连接代码
getSocket( ZMQ::SOCKET_PUSH)
似乎触发 exit() 工作正常。
设置 ZMQ::SOCKOPT_LINGER 似乎并不能阻止 exit() 挂起:
$msgAckPuller->setSockOpt(ZMQ::SOCKOPT_LINGER, 10);
我对 ZMQ 和 ReactPHP 的了解有限,所以我只是关闭问题并将上面的信息留给将来参考。
我用最少的测试代码向 GitHub 上的 React 存储库报告了这个问题。
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');
感谢大家参与讨论。
下一个:不同类型的异常返回状态代码
评论
kill -9
kill
ZMQ::SOCKOPT_LINGER
connect()
$socket->setSockOpt(ZMQ::SOCKOPT_LINGER, 10);