我也有过相关问题。让我解释。我有一个像下载器一样工作的 php '守护进程'。它定期访问提要并从网络下载(laaaarge)内容。守护进程必须在某个时间停止,比如说早上 0500,以防止它在白天使用整个带宽。我决定使用 cronjob 将 SIGTERM 发送到 0500 的守护进程。
在守护程序中,我有以下代码:
pcntl_signal(SIGTERM, array($this, 'signal_handler'));
signal_handler
看起来像这样:
public function signal_handler($signal) {
// some cleanup code
exit(1);
}
不幸的是,这不起作用:|
我花了一段时间才知道发生了什么。我首先想到的是,我必须pcntl_signal_dispatch()
在 init 上调用该方法才能完全启用信号调度。引用文档(评论):
如果您将 PHP 作为 CLI 和“守护程序”(即在循环中)运行,则必须在每个循环中调用此函数以检查是否有新信号正在等待分派。
好的,到目前为止,它似乎工作。但我很快意识到,在某些条件下,即使这样也不会按预期工作。有时守护进程只能被阻止kill -9
- 就像以前一样。:|
那么问题出在哪里?.. 答:我的程序调用wget
通过shell_exec
. 问题是,shell_exec()
阻塞一直等到子进程终止。在此阻塞等待期间,未完成任何信号处理,只能使用 SIGKILL 终止该进程——这很难。还有一个问题是子进程必须一个一个地终止,因为它们在杀死父亲后变成了僵尸进程。
我对此的解决方案是使用子进程执行子进程,proc_open()
并stream_select()
在其输出上使用非阻塞 IO。
现在它就像一个魅力。:) 如果您需要更多信息,请随时发表评论。
注意如果您使用的是 PHP < 5.3,那么您必须使用 `
declare(ticks=1);
而不是pcntl_signal_dispatch()
. 您可以参考相关文档pcntl_signal()
。但如果可能的话,你应该升级到 PHP >= 5.3