我们正在运行一个 PHP 守护进程,它查看队列、接收工作任务并派生工作人员来处理它。在继续之前,工作人员自己会锁定特定位置。
我们将守护进程生成为 nohup 后台进程。
整个体系结构似乎都可以工作,除非我们出于某种原因必须终止进程。如果我们使用 -9 杀死它们,则无法将其困在工作进程中并在死亡前释放锁。
如果我们使用小于 -9 的值(如 TERM 或 HUP),它似乎不会被守护进程或工作进程接收。
有没有人以更好的方式解决了这个问题?
(ps:顺便说一句,出于其他考虑,我们可能无法更改我们的实现语言,所以请只考虑基于 PHP 的解决方案)
最佳答案
我也遇到过相关问题。让我解释。我有一个像下载器一样工作的 php“守护进程”。它定期访问提要并从网上下载 (laaaarge) 内容。守护进程必须在某个时间停止,比如说早上 0500 以防止它在白天使用整个带宽。我决定使用 cronjob 在 0500 将 SIGTERM 发送到守护进程。
在守护进程中我有以下代码:
pcntl_signal(SIGTERM, array($this, 'signal_handler'));
signal_handler
看起来像这样:
public function signal_handler($signal) {
// some cleanup code
exit(1);
}
不幸的是,这没有用:|
我花了一些时间才弄清楚发生了什么。我想到的第一件事是我必须调用方法 pcntl_signal_dispatch()
在 init 上启用信号调度。引自文档 ( comments ):
If you are running PHP as CLI and as a "daemon" (i.e. in a loop), this function must be called in each loop to check if new signals are waiting dispatching.
好的,到目前为止,它似乎有效。但我很快意识到,在某些情况下,即使这样也无法按预期工作。有时守护进程只能被 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
关于php - 将 PHP 进程作为守护进程运行,同时从后台安全地终止它,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15286264/