首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >将PHP进程作为守护进程运行,同时安全地从后台终止它

将PHP进程作为守护进程运行,同时安全地从后台终止它
EN

Stack Overflow用户
提问于 2013-03-08 11:34:12
回答 3查看 1.5K关注 0票数 4

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

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

这整个架构似乎都能工作,除了我们必须杀死进程的时候,不管是什么原因。如果我们使用-9杀死它们,就没有办法在工作进程中捕获它,并在死之前释放锁。

如果我们使用小于-9的值(如TERM或HUP),则守护进程或辅助进程似乎都不会收到它。

有没有人用更好的方法解决了这个问题?

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

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2013-03-09 00:50:16

我也有过相关的问题。让我解释一下。我有一个像下载程序一样工作的php 'daemon‘。它定期访问feed,并从网上下载(laaaarge)内容。守护进程必须在某个时间停止,比方说早上5点,以防止它在白天使用整个带宽。我决定使用cronjob将SIGTERM发送到位于0500的守护进程。

在守护进程中,我有以下代码:

代码语言:javascript
运行
复制
pcntl_signal(SIGTERM, array($this, 'signal_handler'));

其中signal_handler看起来像这样:

代码语言:javascript
运行
复制
public function signal_handler($signal) {
    // some cleanup code 
    exit(1);
}

不幸的是,这不起作用:|

我花了一段时间才弄清楚到底是怎么回事。我想到的第一件事是,我必须在init上调用方法pcntl_signal_dispatch()来启用信号分派。引用文档(comments):

如果你运行PHP作为命令行界面和“守护进程”(即在一个循环中),这个函数必须在每个循环中被调用,以检查是否有新的信号在等待调度。

好的,到目前为止,它似乎起作用了。但我很快意识到,在某些情况下,即使这样也不会像预期的那样工作。有时守护进程只能由kill -9停止-就像以前一样。:

那么问题出在哪里呢?答:我的程序调用wget通过shell_exec下载文件。问题是,shell_exec()阻塞会一直等待到子进程终止。在此阻塞等待期间,未进行任何信号处理,只能使用SIGKILL终止进程-这是最难的。另一个问题是,子进程必须一个接一个地终止,因为它们在杀死父亲后成为僵尸进程。

我对此的解决方案是使用proc_open()执行子进程,并在其输出上使用stream_select()以实现非阻塞IO。

现在它就像一个护身符一样起作用。:)如果你需要更多的信息,请不要犹豫,留下评论。

注意:如果你使用的是< 5.3版本的PHP,那么你必须使用`

代码语言:javascript
运行
复制
declare(ticks=1);

而不是pcntl_signal_dispatch()。关于这一点,您可以参考pcntl_signal()的文档。但如果可能的话,您应该升级到PHPP5.3 >=

票数 3
EN

Stack Overflow用户

发布于 2013-03-15 14:27:02

只需添加标记即可解决此问题:

代码语言:javascript
运行
复制
// tick use required as of PHP 4.3.0
declare(ticks = 1);

不去管它会导致我的代码不能工作。

*(不幸的是,pcntl_signal的文档并没有以更吸引人的方式提到它。)*

票数 1
EN

Stack Overflow用户

发布于 2013-03-08 11:38:50

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

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/15286264

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档