4

我们正在运行一个 PHP 守护程序,它查看队列,接收工作人员作业并生成工作人员来处理它。工人自己在继续之前获得特定位置的锁定。

我们将守护进程生成为 nohup 后台进程。

整个架构似乎都可以工作,除非我们出于某种原因必须终止进程。如果我们使用 -9 杀死它们,则无法将其捕获在工作进程中并在死前释放锁。

如果我们使用小于 -9 的任何东西(如 TERM 或 HUP),它似乎不会被守护进程或工作进程接收。

有没有人以更好的方式解决了这个问题?

(ps:顺便说一句,由于其他考虑,我们可能无法更改我们的实现语言,所以请只考虑基于 PHP 的解决方案)

4

3 回答 3

3

我也有过相关问题。让我解释。我有一个像下载器一样工作的 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

于 2013-03-08T16:50:15.950 回答
1

只需添加刻度即可解决问题:

// tick use required as of PHP 4.3.0
declare(ticks = 1);

不理会这会导致我的代码无法工作。

*(不幸的是 pcntl_signal 的文档并没有以更引人注目的方式提及它。)*

于 2013-03-15T06:27:01.833 回答
0

您需要捕捉信号(SIGTERM)。这可以通过函数pcntl_signal来实现。这将使您可以选择在调用 exit 之前执行任何必要的功能。

于 2013-03-08T03:38:49.657 回答