Php 如何防止upstart杀死守护进程的子进程? 处境

Php 如何防止upstart杀死守护进程的子进程? 处境,php,parallel-processing,signals,daemon,upstart,Php,Parallel Processing,Signals,Daemon,Upstart,我有一个用PHP编写的守护进程(这不是最好的语言,但与我一起工作),它可以从队列接收作业,并在需要完成作业时处理它们。对于每个新作业,我都会将作业分为一个子流程。在这个子进程中,我随后使用执行用于音频转码的长时间运行的系统命令,完成后直接返回到子进程。作业完成后,子进程退出并由父进程清理 为了使这个守护进程始终运行,我使用upstart。这是我的upstart配置文件: description "Audio Transcoding Daemon" start on startup stop o

我有一个用PHP编写的守护进程(这不是最好的语言,但与我一起工作),它可以从队列接收作业,并在需要完成作业时处理它们。对于每个新作业,我都会将作业分为一个子流程。在这个子进程中,我随后使用执行用于音频转码的长时间运行的系统命令,完成后直接返回到子进程。作业完成后,子进程退出并由父进程清理

为了使这个守护进程始终运行,我使用upstart。这是我的upstart配置文件:

description "Audio Transcoding Daemon"

start on startup
stop on shutdown
# kill signal SIGCHLD
kill timeout 1200 # Don't force kill the process until it runs over 20 minutes
respawn

exec audio-daemon.php
目标 因为我希望在分布式环境中使用这个守护进程,所以我希望能够随时关闭服务器,而不会中断任何正在运行的作业。为了做到这一点,我已经在父进程上实现了使用for SIGTERM、SIGHUP和SIGINT的信号处理程序,它在退出自身之前会等待所有子进程正常退出。孩子们也有信号处理器,但是他们被要求忽略所有的杀戮信号

问题 问题是,根据

kill信号节指定的信号被发送到主流程的流程组。(这样,属于作业主进程的所有进程都被终止)。默认情况下,此信号为SIGTERM

这是令人担忧的,因为在我的子进程中,我通过运行系统命令,这也会产生新的子进程。因此,每当我运行
sudo stop audio daemon
,这个子进程(碰巧)就会立即被终止,并且作业返回时会出现一个错误。很明显,sox服从SIGTERM并按指示行事

最初,我想,“好吧。我只需更改
kill signal
,发送一些本来就被忽略的东西,然后只在主进程中拾取它。”但根据,默认情况下只有两个信号被忽略:SIGCHLD和SIGURG(可能还有SIGWINCH)。但是我害怕得到错误的标志,因为这些也可以通过其他方式触发

有几种方法可以使用所谓的“实时信号”创建自定义信号,但它也说明

未经处理的实时信号的默认操作是终止接收过程

所以这没用

你能想出什么办法让upstart保持我所有的子进程开放直到它们完成吗?我真的不想去挖掘sox的源代码来修改它的信号处理程序,虽然我可以将SIGCHLD、SIGURG或SIGWINCH设置为我的暴发户杀戮信号,并祈祷没有其他东西能按我的方式发送给他们,但我忍不住认为有更好的方法来做到这一点。。。有什么想法吗


谢谢你的帮助!:)

因为我还没有收到任何其他关于如何更好地完成这项工作的答案,这就是我最终所做的,我希望它能帮助其他人

要暂停关闭/重新启动系统直到守护进程完成,我更改了upstart配置中的
start on
stop on
。为了防止upstart杀死我的孩子,我求助于使用SIGURG作为我的
杀死信号
,然后我只在我的主守护进程中捕获它作为杀死信号

以下是我的最终upstart配置:

description "Audio Transcoding Daemon"

start on runlevel [2345]
stop on starting rc RUNLEVEL=[016] # Block shutdown/reboot until the daemon ends

kill signal SIGURG # Kill the process group with SIGURG instead of SIGTERM so only the main process will pick it up (since SIGURG will be ignored by all children by default)

kill timeout 1200 # Don't force kill the process until it runs over 20 minutes

respawn

exec audio-daemon.php
请注意,在启动rc运行级别时使用
stop=[016]
是暂停关机/重新启动所必需的<代码>在运行级别停止[016]将不起作用

还请注意,如果您在应用程序中出于任何其他原因使用SIGURG,则将其用作终止信号可能会导致问题。就我而言,我不是,所以就我所知,这一切都很好

理想情况下,如果POSIX标准提供了一个用户定义的信号,比如默认情况下被忽略的SIGUSR1和SIGUSR2,那就更好了。但现在,它似乎不存在


如果您有更好的答案,请随时加入,但现在,我希望这能帮助其他有此问题的人。

免责声明:我不懂任何PHP

通过为已启动的子流程设置新的组id,我解决了ruby流程中的类似问题。看起来php有一个新的功能

通过将组id设置为进程id,可以启动一个新组(从
audio daemon.php中分离)

差不多

$chldPid=pcntl_fork()
... << error checks etc
 if ($chldPid){
    ...
    posix_setpgid($chldPid, $chldPid)
$chldPid=pcntl_fork()

... 请注意,
pcntl\u fork
返回父进程的pid,而不是子进程的pid。因此,您正在为父进程而不是子进程设置不同的进程组id<代码>pcntl_fork()==0
=>子级<代码>pcntl_fork()>0
=>父级<代码>pcntl_fork()<0=>无法分叉。为了得到孩子的pid调用
posix_getpid
@Basti我是误读了吗?“成功时,子进程的PID在父进程的执行线程中返回”这就是我要说的:
pcntl\u fork
在父进程中返回子进程的PID,在子进程中返回
0
。您的条件
if($chldPid)
对于父进程计算为
true
,对于子进程计算为
false
。这意味着您是在父进程中设置组id,而不是在子进程中设置组id:-)好吧,我收回这一点:实际上,调用posix_setpgid($pid,$gid)的位置并不重要,因为您正在指定新的
$gid
应该获得什么。根据需要,您应该在父进程和子进程中调用
posix_setpgid
,以避免出现争用情况。但我不知道这些信息有多准确。在child中,您只需
posix_setpgid(0,0)
。这将把进程的组id设置为它的进程id。干杯!如果你坚持总是从一个地方(总是在家长或孩子)设置比赛条件,我怀疑比赛条件是否存在。注:我知道没有PHPI在这里有非常类似的情况。。。我还在守护进程中执行了一个PHP脚本,但是这个脚本使用
system
调用执行另一个PHP脚本。作为