如何防止upstart将子进程杀死到守护进程?

时间:2014-01-17 05:33:01

标签: php parallel-processing signals daemon upstart

情况

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

为了让这个守护进程始终运行,我使用了暴发。这是我的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

目标

因为我想在分布式环境中使用这个守护进程,所以我希望能够在不中断任何正在运行的作业的情况下随时关闭服务器。为此,我已经在父进程上使用pcntl_signal()为SIGTERM,SIGHUP和SIGINT实现了信号处理程序,它等待所有子进程在退出之前正常退出。孩子们也有信号处理程序,但他们会忽略所有杀戮信号。

问题

根据docs ...

,问题是
  

kill信号节指定的信号被发送到主进程的进程组。 (这样就可以杀死属于作业主进程的所有进程)。默认情况下,此信号为SIGTERM。

这很令人担忧,因为在我的子进程中,我通过proc_open()运行系统命令,这也会产生新的子进程。因此,每当我运行sudo stop audio-daemon时,此子进程(恰好是sox)将立即被终止,并且作业将返回并返回错误。显然,sox服从SIGTERM并做了它所说的......

最初,我想,“很好。我只是改变kill signal发送一些本来就被忽略的东西,我只会在主过程中把它拿起来。”但根据manual,默认情况下只有两个信号被忽略:SIGCHLD和SIGURG(可能还有SIGWINCH)。但我害怕得到假旗,因为这些也可以通过其他方式触发。

有多种方法可以使用manual调用“实时信号”来创建自定义信号,但它也声明......

  

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

所以这没有帮助......

您是否可以想到任何方式可以让我的所有子流程在完成之前保持开放状态?我真的不想去挖掘sox的源代码来修改它的信号处理程序,虽然我可以设置SIGCHLD,SIGURG或SIGWINCH作为我的暴发终止信号并祈祷没有别的东西发送给我,我忍不住认为有更好的方法来做到这一点......任何想法?

感谢您的帮助! :)

2 个答案:

答案 0 :(得分:4)

由于我没有收到任何关于如何更好地做到这一点的其他答案,这就是我最终做的事情,我希望它可以帮助那些人......

要停止关闭/重启系统直到守护程序完成,我在我的upstart配置中更改了start onstop on。为了让新手免于杀死我的孩子,我使用了SIGURG作为我的kill signal,然后我只在主守护进程中捕获了一个终止信号。

这是我最后的新贵配置:

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

请注意,使用stop on starting rc RUNLEVEL=[016]是停止关机/重启的必要条件。 stop on runlevel [016]无效。

另请注意,如果您因任何其他原因在应用程序中使用SIGURG,将其用作终止信号可能会导致问题。在我的情况下,我不是,所以就我所知,这个工作正常。

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

如果你有更好的答案,请随意加入,但就目前而言,我希望这可以帮助其他人解决这个问题。

答案 1 :(得分:1)

免责声明:我不知道任何PHP

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

您可以通过将其组ID设置为其进程ID来启动新组(从audio-daemon.php分离)

类似

$chldPid=pcntl_fork()
... << error checks etc
 if ($chldPid){
    ...
    posix_setpgid($chldPid, $chldPid)
相关问题