我有一个无限期运行的PHP脚本,我正在努力使它能够在收到SIGTERM信号时正常关闭。此脚本是大型Symfony2代码库的一部分,因此“脚本”实际上是一个由命令启动的服务。基本上,我在服务类$shouldBeAlive
中有一个布尔值。我有一个while(true)
循环,用于检查每次迭代开始时$shouldBeAlive
是否仍然为真。然后我有一个信号处理程序,它在while(true)
循环启动之前设置,如果抛出SIGTERM,则将$shouldBeAlive
设置为false,这样循环将完成当前迭代,然后立即退出在下一次迭代开始时。
在我对信号和诸如此类的理解中,所有这一切都应该可行。但相反,每次我将SIGTERM发送到php进程(我使用Segmentation fault: 11
)时,我都会收到一条消息kill <pid>
。我已经尝试使用Xdebug跟踪来找到问题的根源,但我无法从中找出一个明显的问题(同样,Xdebug生成的跟踪文件是8-10MB)。
以下是我的服务类的简化版本:
class WorkerService extends AbstractService
{
private $shouldBeAlive;
// called by the constructor of this class
protected function setup()
{
$this->shouldBeAlive = false;
}
// called when my command wants to make the work begin
public function go()
{
$this->shouldBeAlive = true;
// set signal handler to `$this->handleSignal($signo)`
assert(pcntl_signal(SIGTERM, [$this, "handleSignal"]));
$this->work();
}
public function handleSignal($signo)
{
// make the worker terminate on next loop completion
$this->shouldBeAlive = false;
// restore the default handler for this signal
assert(pcntl_signal($signo, SIG_DFL));
echo "Signal received, shutting down gracefully... (send signal again to force immediate shutdown)";
return;
}
public function work()
{
while (true) {
// make PHP fire any waiting signals
pcntl_signal_dispatch();
// break out of the loop if we're supposed to be dead
if (!$this->shouldBeAlive) break;
// ...
// I'm omitting the actual loop logic. Basically, it makes some
// HTTP requests, sometimes starts another process with proc_open(),
// and eventually it'll sleep for a couple seconds and continue.
}
}
}
似乎我的handleSignal($ signo)方法根本就没有被调用过,因为没有多少调整可以解决这个问题。我也尝试在go()方法中使用declare(ticks = 1);
而不是在while(true)循环中调用pcntl_signal_dispatch();
,它仍然是段错误(以及我理解事物的方式,这样做反正没有意义)。有谁看到我可能会遗漏或误解?